--- /dev/null
+// Example program for matching summary functions and synthetic child providers.
+//
+// The classes here simulate code generated by a serialization tool like, for
+// example, protocol buffers. But the actual "generated" class layout is
+// extremely naive to simplify the example.
+//
+// The idea is that we want to have generic formatters for a bunch of message
+// classes, because they are all generated following common patterns, but the
+// matching can't be based in the type name, because it can be anything.
+
+#include <string>
+
+class Message {
+ // Dummy method definitions to illustrate a possible generic message API.
+ std::string serialize() { return "TODO"; }
+ Message* deserialize() {
+ return nullptr; // TODO.
+ }
+};
+
+// This class could have been generated from a description like this. Assume
+// fields are always optional, for simplicity (e.g. we don't care during
+// serialization if a Customer has a name or not, we're just moving data around
+// and validation happens elsewhere).
+//
+// message Customer {
+// string name;
+// int age;
+// string address;
+// }
+class Customer : public Message {
+ private:
+ int _internal_bookkeeping_bits_;
+
+ // Presence bits. They are true if the field has been set.
+ bool _has_name_ = false;
+ bool _has_age_ = false;
+ bool _has_address_ = false;
+
+ // Actual field data.
+ std::string name_;
+ int age_;
+ std::string address_;
+
+ public:
+ // Getters and setters.
+ bool has_name() { return _has_name_; }
+ bool has_age() { return _has_age_; }
+ bool has_address() { return _has_address_; }
+
+ std::string name() { return name_; }
+ int age() { return age_; }
+ std::string address() { return address_; }
+
+ void set_name(std::string name) {
+ name_ = name;
+ _has_name_ = true;
+ }
+ void set_age(int age) {
+ age_ = age;
+ _has_age_ = true;
+ }
+ void set_address(std::string address) {
+ address_ = address;
+ _has_address_ = true;
+ }
+};
+
+// message ProductOrder {
+// string product_name;
+// int amount;
+// }
+class ProductOrder : public Message {
+ private:
+ int _internal_bookkeeping_bits_;
+
+ // Presence bits. They are true if the field has been set.
+ bool _has_product_name_ = false;
+ bool _has_amount_ = false;
+
+ // Actual field data.
+ std::string product_name_;
+ int amount_;
+
+ public:
+ // Getters and setters.
+ bool has_product_name() { return _has_product_name_; }
+ bool has_amount() { return _has_amount_; }
+
+ std::string get_product_name() { return product_name_; }
+ int get_amount() { return amount_; }
+
+ void set_product_name(std::string product_name) {
+ product_name_ = product_name;
+ _has_product_name_ = true;
+ }
+ void set_amount(int amount) {
+ amount_ = amount;
+ _has_amount_ = true;
+ }
+};
+
+int main(int argc, char **argv) {
+ Customer customer;
+ customer.set_name("C. Ustomer");
+ customer.set_address("123 Fake St.");
+ // no age, so we can check absent fields get omitted.
+
+ ProductOrder order;
+ order.set_product_name("widget");
+ order.set_amount(100);
+ return 0; // break here.
+}
+
public:
TypeSummaryImpl::Flags m_flags;
StringList m_target_types;
- bool m_regex;
+ FormatterMatchType m_match_type;
ConstString m_name;
std::string m_category;
- ScriptAddOptions(const TypeSummaryImpl::Flags &flags, bool regx,
- ConstString name, std::string catg)
- : m_flags(flags), m_regex(regx), m_name(name), m_category(catg) {}
+ ScriptAddOptions(const TypeSummaryImpl::Flags &flags,
+ FormatterMatchType match_type, ConstString name,
+ std::string catg)
+ : m_flags(flags), m_match_type(match_type), m_name(name),
+ m_category(catg) {}
typedef std::shared_ptr<ScriptAddOptions> SharedPointer;
};
bool m_skip_pointers;
bool m_skip_references;
bool m_cascade;
- bool m_regex;
+ FormatterMatchType m_match_type;
StringList m_target_types;
std::string m_category;
- SynthAddOptions(bool sptr, bool sref, bool casc, bool regx, std::string catg)
+ SynthAddOptions(bool sptr, bool sref, bool casc,
+ FormatterMatchType match_type, std::string catg)
: m_skip_pointers(sptr), m_skip_references(sref), m_cascade(casc),
- m_regex(regx), m_category(catg) {}
+ m_match_type(match_type), m_category(catg) {}
typedef std::shared_ptr<SynthAddOptions> SharedPointer;
};
// Instance variables to hold the values for command options.
TypeSummaryImpl::Flags m_flags;
- bool m_regex = false;
+ FormatterMatchType m_match_type = eFormatterMatchExact;
std::string m_format_string;
ConstString m_name;
std::string m_python_script;
bool Execute_StringSummary(Args &command, CommandReturnObject &result);
public:
- enum SummaryFormatType { eRegularSummary, eRegexSummary, eNamedSummary };
-
CommandObjectTypeSummaryAdd(CommandInterpreter &interpreter);
~CommandObjectTypeSummaryAdd() override = default;
Status error;
for (const std::string &type_name : options->m_target_types) {
- CommandObjectTypeSummaryAdd::AddSummary(
- ConstString(type_name), script_format,
- (options->m_regex
- ? CommandObjectTypeSummaryAdd::eRegexSummary
- : CommandObjectTypeSummaryAdd::eRegularSummary),
- options->m_category, &error);
+ AddSummary(ConstString(type_name), script_format,
+ options->m_match_type, options->m_category,
+ &error);
if (error.Fail()) {
error_sp->Printf("error: %s", error.AsCString());
error_sp->Flush();
}
if (options->m_name) {
- CommandObjectTypeSummaryAdd::AddSummary(
- options->m_name, script_format,
- CommandObjectTypeSummaryAdd::eNamedSummary,
- options->m_category, &error);
+ CommandObjectTypeSummaryAdd::AddNamedSummary(
+ options->m_name, script_format, &error);
if (error.Fail()) {
- CommandObjectTypeSummaryAdd::AddSummary(
- options->m_name, script_format,
- CommandObjectTypeSummaryAdd::eNamedSummary,
- options->m_category, &error);
+ CommandObjectTypeSummaryAdd::AddNamedSummary(
+ options->m_name, script_format, &error);
if (error.Fail()) {
error_sp->Printf("error: %s", error.AsCString());
error_sp->Flush();
io_handler.SetIsDone(true);
}
- static bool AddSummary(ConstString type_name, lldb::TypeSummaryImplSP entry,
- SummaryFormatType type, std::string category,
- Status *error = nullptr);
+ bool AddSummary(ConstString type_name, lldb::TypeSummaryImplSP entry,
+ FormatterMatchType match_type, std::string category,
+ Status *error = nullptr);
+
+ bool AddNamedSummary(ConstString summary_name, lldb::TypeSummaryImplSP entry,
+ Status *error = nullptr);
protected:
bool DoExecute(Args &command, CommandReturnObject &result) override;
m_category = std::string(option_arg);
break;
case 'x':
- m_regex = true;
+ if (m_match_type == eFormatterMatchCallback)
+ error.SetErrorString(
+ "can't use --regex and --recognizer-function at the same time");
+ else
+ m_match_type = eFormatterMatchRegex;
+ break;
+ case '\x01':
+ if (m_match_type == eFormatterMatchRegex)
+ error.SetErrorString(
+ "can't use --regex and --recognizer-function at the same time");
+ else
+ m_match_type = eFormatterMatchCallback;
break;
default:
llvm_unreachable("Unimplemented option");
m_category = "default";
is_class_based = false;
handwrite_python = false;
- m_regex = false;
+ m_match_type = eFormatterMatchExact;
}
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
std::string m_category;
bool is_class_based;
bool handwrite_python;
- bool m_regex;
+ FormatterMatchType m_match_type;
};
CommandOptions m_options;
for (const std::string &type_name : options->m_target_types) {
if (!type_name.empty()) {
- if (!CommandObjectTypeSynthAdd::AddSynth(
- ConstString(type_name), synth_provider,
- options->m_regex
- ? CommandObjectTypeSynthAdd::eRegexSynth
- : CommandObjectTypeSynthAdd::eRegularSynth,
- options->m_category, &error)) {
+ if (AddSynth(ConstString(type_name), synth_provider,
+ options->m_match_type, options->m_category,
+ &error)) {
error_sp->Printf("error: %s\n", error.AsCString());
error_sp->Flush();
break;
}
public:
- enum SynthFormatType { eRegularSynth, eRegexSynth };
-
CommandObjectTypeSynthAdd(CommandInterpreter &interpreter);
~CommandObjectTypeSynthAdd() override = default;
- static bool AddSynth(ConstString type_name, lldb::SyntheticChildrenSP entry,
- SynthFormatType type, std::string category_name,
- Status *error);
+ bool AddSynth(ConstString type_name, lldb::SyntheticChildrenSP entry,
+ FormatterMatchType match_type, std::string category_name,
+ Status *error);
};
// CommandObjectTypeFormatAdd
m_flags.SetSkipReferences(true);
break;
case 'x':
- m_regex = true;
+ if (m_match_type == eFormatterMatchCallback)
+ error.SetErrorString(
+ "can't use --regex and --recognizer-function at the same time");
+ else
+ m_match_type = eFormatterMatchRegex;
+ break;
+ case '\x01':
+ if (m_match_type == eFormatterMatchRegex)
+ error.SetErrorString(
+ "can't use --regex and --recognizer-function at the same time");
+ else
+ m_match_type = eFormatterMatchCallback;
break;
case 'n':
m_name.SetString(option_arg);
.SetSkipReferences(false)
.SetHideItemNames(false);
- m_regex = false;
+ m_match_type = eFormatterMatchExact;
m_name.Clear();
m_python_script = "";
m_python_function = "";
} else {
// Use an IOHandler to grab Python code from the user
auto options = std::make_unique<ScriptAddOptions>(
- m_options.m_flags, m_options.m_regex, m_options.m_name,
+ m_options.m_flags, m_options.m_match_type, m_options.m_name,
m_options.m_category);
for (auto &entry : command.entries()) {
Status error;
for (auto &entry : command.entries()) {
- CommandObjectTypeSummaryAdd::AddSummary(
- ConstString(entry.ref()), script_format,
- (m_options.m_regex ? eRegexSummary : eRegularSummary),
- m_options.m_category, &error);
+ AddSummary(ConstString(entry.ref()), script_format, m_options.m_match_type,
+ m_options.m_category, &error);
if (error.Fail()) {
result.AppendError(error.AsCString());
return false;
}
if (m_options.m_name) {
- AddSummary(m_options.m_name, script_format, eNamedSummary,
- m_options.m_category, &error);
+ AddNamedSummary(m_options.m_name, script_format, &error);
if (error.Fail()) {
result.AppendError(error.AsCString());
result.AppendError("added to types, but not given a name");
}
ConstString typeCS(arg_entry.ref());
- AddSummary(typeCS, entry,
- (m_options.m_regex ? eRegexSummary : eRegularSummary),
- m_options.m_category, &error);
+ AddSummary(typeCS, entry, m_options.m_match_type, m_options.m_category,
+ &error);
if (error.Fail()) {
result.AppendError(error.AsCString());
}
if (m_options.m_name) {
- AddSummary(m_options.m_name, entry, eNamedSummary, m_options.m_category,
- &error);
+ AddNamedSummary(m_options.m_name, entry, &error);
if (error.Fail()) {
result.AppendError(error.AsCString());
result.AppendError("added to types, but not given a name");
return false;
}
+bool CommandObjectTypeSummaryAdd::AddNamedSummary(ConstString summary_name,
+ TypeSummaryImplSP entry,
+ Status *error) {
+ // system named summaries do not exist (yet?)
+ DataVisualization::NamedSummaryFormats::Add(summary_name, entry);
+ return true;
+}
+
bool CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name,
TypeSummaryImplSP entry,
- SummaryFormatType type,
+ FormatterMatchType match_type,
std::string category_name,
Status *error) {
-
- // Named summaries are a special case, they exist in their own map in the
- // FormatManager, outside of any categories.
- if (type == eNamedSummary) {
- // system named summaries do not exist (yet?)
- DataVisualization::NamedSummaryFormats::Add(type_name, entry);
- return true;
- }
-
lldb::TypeCategoryImplSP category;
DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()),
category);
- if (type == eRegularSummary) {
+ if (match_type == eFormatterMatchExact) {
if (FixArrayTypeNameWithRegex(type_name))
- type = eRegexSummary;
+ match_type = eFormatterMatchRegex;
}
- FormatterMatchType match_type = eFormatterMatchExact;
- if (type == eRegexSummary) {
+ if (match_type == eFormatterMatchRegex) {
match_type = eFormatterMatchRegex;
RegularExpression typeRX(type_name.GetStringRef());
if (!typeRX.IsValid()) {
return false;
}
}
+
+ if (match_type == eFormatterMatchCallback) {
+ const char *function_name = type_name.AsCString();
+ ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
+ if (interpreter && !interpreter->CheckObjectExists(function_name)) {
+ error->SetErrorStringWithFormat(
+ "The provided recognizer function \"%s\" does not exist - "
+ "please define it before attempting to use this summary.\n",
+ function_name);
+ return false;
+ }
+ }
category->AddTypeSummary(type_name.GetStringRef(), match_type, entry);
return true;
}
Args &command, CommandReturnObject &result) {
auto options = std::make_unique<SynthAddOptions>(
m_options.m_skip_pointers, m_options.m_skip_references,
- m_options.m_cascade, m_options.m_regex, m_options.m_category);
+ m_options.m_cascade, m_options.m_match_type, m_options.m_category);
for (auto &entry : command.entries()) {
if (entry.ref().empty()) {
}
ConstString typeCS(arg_entry.ref());
- if (!AddSynth(typeCS, entry,
- m_options.m_regex ? eRegexSynth : eRegularSynth,
- m_options.m_category, &error)) {
+ if (!AddSynth(typeCS, entry, m_options.m_match_type, m_options.m_category,
+ &error)) {
result.AppendError(error.AsCString());
return false;
}
bool CommandObjectTypeSynthAdd::AddSynth(ConstString type_name,
SyntheticChildrenSP entry,
- SynthFormatType type,
+ FormatterMatchType match_type,
std::string category_name,
Status *error) {
lldb::TypeCategoryImplSP category;
DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()),
category);
- if (type == eRegularSynth) {
+ if (match_type == eFormatterMatchExact) {
if (FixArrayTypeNameWithRegex(type_name))
- type = eRegexSynth;
+ match_type = eFormatterMatchRegex;
}
// Only check for conflicting filters in the same category if `type_name` is
// an actual type name. Matching a regex string against registered regexes
// doesn't work.
- if (type == eRegularSynth) {
+ if (match_type == eFormatterMatchExact) {
// It's not generally possible to get a type object here. For example, this
// command can be run before loading any binaries. Do just a best-effort
// name-based lookup here to try to prevent conflicts.
}
}
- FormatterMatchType match_type = eFormatterMatchExact;
- if (type == eRegexSynth) {
- match_type = eFormatterMatchRegex;
+ if (match_type == eFormatterMatchRegex) {
RegularExpression typeRX(type_name.GetStringRef());
if (!typeRX.IsValid()) {
if (error)
}
}
+ if (match_type == eFormatterMatchCallback) {
+ const char *function_name = type_name.AsCString();
+ ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
+ if (interpreter && !interpreter->CheckObjectExists(function_name)) {
+ error->SetErrorStringWithFormat(
+ "The provided recognizer function \"%s\" does not exist - "
+ "please define it before attempting to use this summary.\n",
+ function_name);
+ return false;
+ }
+ }
+
category->AddTypeSynthetic(type_name.GetStringRef(), match_type, entry);
return true;
}