Option --regex (-x) now also works for synthetic children:
- Added a test case in python-synth Minor code improvements in categories, making them ready for adding new element types llvm-svn: 136957
This commit is contained in:
parent
2536b51aae
commit
f1af1ed6d2
|
@ -632,6 +632,17 @@ private:
|
|||
|
||||
public:
|
||||
|
||||
enum FormatCategoryItem
|
||||
{
|
||||
eSummary = 0x0001,
|
||||
eRegexSummary = 0x1001,
|
||||
eFilter = 0x0002,
|
||||
eRegexFilter = 0x1002,
|
||||
};
|
||||
|
||||
typedef uint16_t FormatCategoryItems;
|
||||
static const uint16_t ALL_ITEM_TYPES = 0xFFFF;
|
||||
|
||||
typedef SummaryNavigator::SharedPointer SummaryNavigatorSP;
|
||||
typedef RegexSummaryNavigator::SharedPointer RegexSummaryNavigatorSP;
|
||||
typedef FilterNavigator::SharedPointer FilterNavigatorSP;
|
||||
|
@ -715,24 +726,59 @@ public:
|
|||
void
|
||||
ClearSummaries()
|
||||
{
|
||||
m_summary_nav->Clear();
|
||||
m_regex_summary_nav->Clear();
|
||||
Clear(eSummary | eRegexSummary);
|
||||
}
|
||||
|
||||
// just a shortcut for (Summary()->Delete(name) || RegexSummary()->Delete(name))
|
||||
bool
|
||||
DeleteSummaries(const char* name)
|
||||
{
|
||||
bool del_sum = m_summary_nav->Delete(name);
|
||||
bool del_rex = m_regex_summary_nav->Delete(name);
|
||||
|
||||
return (del_sum || del_rex);
|
||||
return Delete(name, (eSummary | eRegexSummary));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Clear(FormatCategoryItems items = ALL_ITEM_TYPES)
|
||||
{
|
||||
if ( (items & eSummary) )
|
||||
m_summary_nav->Clear();
|
||||
if ( (items & eRegexSummary) )
|
||||
m_regex_summary_nav->Clear();
|
||||
if ( (items & eFilter) )
|
||||
m_filter_nav->Clear();
|
||||
if ( (items & eRegexFilter) )
|
||||
m_regex_filter_nav->Clear();
|
||||
}
|
||||
|
||||
bool
|
||||
Delete(const char* name,
|
||||
FormatCategoryItems items = ALL_ITEM_TYPES)
|
||||
{
|
||||
bool success = false;
|
||||
if ( (items & eSummary) )
|
||||
success = m_summary_nav->Delete(name) || success;
|
||||
if ( (items & eRegexSummary) )
|
||||
success = m_regex_summary_nav->Delete(name) || success;
|
||||
if ( (items & eFilter) )
|
||||
success = m_filter_nav->Delete(name) || success;
|
||||
if ( (items & eRegexFilter) )
|
||||
success = m_regex_filter_nav->Delete(name) || success;
|
||||
return success;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GetCount()
|
||||
GetCount(FormatCategoryItems items = ALL_ITEM_TYPES)
|
||||
{
|
||||
return Summary()->GetCount() + RegexSummary()->GetCount();
|
||||
uint32_t count = 0;
|
||||
if ( (items & eSummary) )
|
||||
count += m_summary_nav->GetCount();
|
||||
if ( (items & eRegexSummary) )
|
||||
count += m_regex_summary_nav->GetCount();
|
||||
if ( (items & eFilter) )
|
||||
count += m_filter_nav->GetCount();
|
||||
if ( (items & eRegexFilter) )
|
||||
count += m_regex_filter_nav->GetCount();
|
||||
return count;
|
||||
}
|
||||
|
||||
std::string
|
||||
|
|
|
@ -1168,8 +1168,7 @@ private:
|
|||
const FormatCategory::SharedPointer& cate)
|
||||
{
|
||||
const char* name = (const char*)param;
|
||||
cate->Summary()->Delete(name);
|
||||
cate->RegexSummary()->Delete(name);
|
||||
cate->Delete(name, FormatCategory::eSummary | FormatCategory::eRegexSummary);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1892,6 +1891,7 @@ public:
|
|||
//-------------------------------------------------------------------------
|
||||
|
||||
bool CommandObjectTypeSynthList_LoopCallback(void* pt2self, const char* type, const SyntheticFilter::SharedPointer& entry);
|
||||
bool CommandObjectTypeSynthRXList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SyntheticFilter::SharedPointer& entry);
|
||||
|
||||
class CommandObjectTypeSynthList;
|
||||
|
||||
|
@ -2044,6 +2044,12 @@ private:
|
|||
|
||||
cate->Filter()->LoopThrough(CommandObjectTypeSynthList_LoopCallback, param_vp);
|
||||
|
||||
if (cate->RegexFilter()->GetCount() > 0)
|
||||
{
|
||||
result->GetOutputStream().Printf("Regex-based filters (slower):\n");
|
||||
cate->RegexFilter()->LoopThrough(CommandObjectTypeSynthRXList_LoopCallback, param_vp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2059,6 +2065,7 @@ private:
|
|||
}
|
||||
|
||||
friend bool CommandObjectTypeSynthList_LoopCallback(void* pt2self, const char* type, const SyntheticFilter::SharedPointer& entry);
|
||||
friend bool CommandObjectTypeSynthRXList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SyntheticFilter::SharedPointer& entry);
|
||||
};
|
||||
|
||||
bool
|
||||
|
@ -2070,6 +2077,15 @@ CommandObjectTypeSynthList_LoopCallback (void* pt2self,
|
|||
return param->self->LoopCallback(type, entry, param->regex, param->result);
|
||||
}
|
||||
|
||||
bool
|
||||
CommandObjectTypeSynthRXList_LoopCallback (void* pt2self,
|
||||
lldb::RegularExpressionSP regex,
|
||||
const SyntheticFilter::SharedPointer& entry)
|
||||
{
|
||||
CommandObjectTypeSynthList_LoopCallbackParam* param = (CommandObjectTypeSynthList_LoopCallbackParam*)pt2self;
|
||||
return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result);
|
||||
}
|
||||
|
||||
|
||||
OptionDefinition
|
||||
CommandObjectTypeSynthList::CommandOptions::g_option_table[] =
|
||||
|
@ -2157,8 +2173,7 @@ private:
|
|||
const FormatCategory::SharedPointer& cate)
|
||||
{
|
||||
const char* name = (const char*)param;
|
||||
cate->Filter()->Delete(name);
|
||||
return true;
|
||||
return cate->Delete(name, FormatCategory::eFilter | FormatCategory::eRegexFilter);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -2217,6 +2232,7 @@ public:
|
|||
Debugger::Formatting::Categories::Get(ConstString(m_options.m_category), category);
|
||||
|
||||
bool delete_category = category->Filter()->Delete(typeCS.GetCString());
|
||||
delete_category = category->RegexFilter()->Delete(typeCS.GetCString()) || delete_category;
|
||||
|
||||
if (delete_category)
|
||||
{
|
||||
|
@ -2315,7 +2331,7 @@ private:
|
|||
const char* cate_name,
|
||||
const FormatCategory::SharedPointer& cate)
|
||||
{
|
||||
cate->Filter()->Clear();
|
||||
cate->Clear(FormatCategory::eFilter | FormatCategory::eRegexFilter);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
@ -2352,6 +2368,7 @@ public:
|
|||
else
|
||||
Debugger::Formatting::Categories::Get(ConstString(NULL), category);
|
||||
category->Filter()->Clear();
|
||||
category->RegexFilter()->Clear();
|
||||
}
|
||||
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
|
@ -2506,7 +2523,11 @@ public:
|
|||
const char *type_name = options->m_target_types.GetStringAtIndex(i);
|
||||
ConstString typeCS(type_name);
|
||||
if (typeCS)
|
||||
category->Filter()->Add(typeCS.GetCString(), synth_provider);
|
||||
CommandObjectTypeSynthAdd::AddSynth(typeCS,
|
||||
synth_provider,
|
||||
options->m_regex ? CommandObjectTypeSynthAdd::eRegexSynth : CommandObjectTypeSynthAdd::eRegularSynth,
|
||||
options->m_category,
|
||||
NULL);
|
||||
else
|
||||
{
|
||||
out_stream->Printf ("Internal error #6: no script attached.\n");
|
||||
|
@ -2517,319 +2538,242 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class CommandObjectTypeSynthAdd : public CommandObject
|
||||
void
|
||||
CommandObjectTypeSynthAdd::CollectPythonScript (SynthAddOptions *options,
|
||||
CommandReturnObject &result)
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
class CommandOptions : public Options
|
||||
InputReaderSP reader_sp (new TypeSynthAddInputReader(m_interpreter.GetDebugger()));
|
||||
if (reader_sp && options)
|
||||
{
|
||||
typedef std::vector<std::string> option_vector;
|
||||
public:
|
||||
|
||||
CommandOptions (CommandInterpreter &interpreter) :
|
||||
Options (interpreter)
|
||||
InputReaderEZ::InitializationParameters ipr;
|
||||
|
||||
Error err (reader_sp->Initialize (ipr.SetBaton(options).SetPrompt(" ")));
|
||||
if (err.Success())
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
~CommandOptions (){}
|
||||
|
||||
virtual Error
|
||||
SetOptionValue (uint32_t option_idx, const char *option_arg)
|
||||
{
|
||||
Error error;
|
||||
char short_option = (char) m_getopt_table[option_idx].val;
|
||||
bool success;
|
||||
|
||||
switch (short_option)
|
||||
{
|
||||
case 'C':
|
||||
m_cascade = Args::StringToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat("Invalid value for cascade: %s.\n", option_arg);
|
||||
break;
|
||||
case 'c':
|
||||
m_expr_paths.push_back(option_arg);
|
||||
has_child_list = true;
|
||||
break;
|
||||
case 'P':
|
||||
handwrite_python = true;
|
||||
break;
|
||||
case 'l':
|
||||
m_class_name = std::string(option_arg);
|
||||
is_class_based = true;
|
||||
break;
|
||||
case 'p':
|
||||
m_skip_pointers = true;
|
||||
break;
|
||||
case 'r':
|
||||
m_skip_references = true;
|
||||
break;
|
||||
case 'w':
|
||||
m_category = ConstString(option_arg).GetCString();
|
||||
break;
|
||||
default:
|
||||
error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void
|
||||
OptionParsingStarting ()
|
||||
{
|
||||
m_cascade = true;
|
||||
m_class_name = "";
|
||||
m_skip_pointers = false;
|
||||
m_skip_references = false;
|
||||
m_category = NULL;
|
||||
m_expr_paths.clear();
|
||||
is_class_based = false;
|
||||
handwrite_python = false;
|
||||
has_child_list = false;
|
||||
}
|
||||
|
||||
const OptionDefinition*
|
||||
GetDefinitions ()
|
||||
{
|
||||
return g_option_table;
|
||||
}
|
||||
|
||||
// Options table: Required for subclasses of Options.
|
||||
|
||||
static OptionDefinition g_option_table[];
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
|
||||
bool m_cascade;
|
||||
bool m_skip_references;
|
||||
bool m_skip_pointers;
|
||||
std::string m_class_name;
|
||||
bool m_input_python;
|
||||
option_vector m_expr_paths;
|
||||
const char* m_category;
|
||||
|
||||
bool is_class_based;
|
||||
|
||||
bool handwrite_python;
|
||||
|
||||
bool has_child_list;
|
||||
|
||||
typedef option_vector::iterator ExpressionPathsIterator;
|
||||
};
|
||||
|
||||
CommandOptions m_options;
|
||||
|
||||
virtual Options *
|
||||
GetOptions ()
|
||||
{
|
||||
return &m_options;
|
||||
}
|
||||
|
||||
void
|
||||
CollectPythonScript (SynthAddOptions *options,
|
||||
CommandReturnObject &result)
|
||||
{
|
||||
InputReaderSP reader_sp (new TypeSynthAddInputReader(m_interpreter.GetDebugger()));
|
||||
if (reader_sp && options)
|
||||
{
|
||||
|
||||
InputReaderEZ::InitializationParameters ipr;
|
||||
|
||||
Error err (reader_sp->Initialize (ipr.SetBaton(options).SetPrompt(" ")));
|
||||
if (err.Success())
|
||||
{
|
||||
m_interpreter.GetDebugger().PushInputReader (reader_sp);
|
||||
result.SetStatus (eReturnStatusSuccessFinishNoResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.AppendError (err.AsCString());
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
}
|
||||
m_interpreter.GetDebugger().PushInputReader (reader_sp);
|
||||
result.SetStatus (eReturnStatusSuccessFinishNoResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.AppendError("out of memory");
|
||||
result.AppendError (err.AsCString());
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Execute_HandwritePython (Args& command, CommandReturnObject &result)
|
||||
else
|
||||
{
|
||||
SynthAddOptions *options = new SynthAddOptions ( m_options.m_skip_pointers,
|
||||
m_options.m_skip_references,
|
||||
m_options.m_cascade,
|
||||
m_options.m_category);
|
||||
|
||||
const size_t argc = command.GetArgumentCount();
|
||||
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
const char* typeA = command.GetArgumentAtIndex(i);
|
||||
if (typeA && *typeA)
|
||||
options->m_target_types << typeA;
|
||||
else
|
||||
{
|
||||
result.AppendError("empty typenames not allowed");
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CollectPythonScript(options,result);
|
||||
return result.Succeeded();
|
||||
result.AppendError("out of memory");
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Execute_ChildrenList (Args& command, CommandReturnObject &result)
|
||||
{
|
||||
const size_t argc = command.GetArgumentCount();
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_options.m_expr_paths.size() == 0)
|
||||
{
|
||||
result.AppendErrorWithFormat ("%s needs one or more children.\n", m_cmd_name.c_str());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
SyntheticChildrenSP entry;
|
||||
|
||||
SyntheticFilter* impl = new SyntheticFilter(m_options.m_cascade,
|
||||
m_options.m_skip_pointers,
|
||||
m_options.m_skip_references);
|
||||
|
||||
entry.reset(impl);
|
||||
|
||||
// go through the expression paths
|
||||
CommandOptions::ExpressionPathsIterator begin, end = m_options.m_expr_paths.end();
|
||||
|
||||
for (begin = m_options.m_expr_paths.begin(); begin != end; begin++)
|
||||
impl->AddExpressionPath(*begin);
|
||||
|
||||
|
||||
// now I have a valid provider, let's add it to every type
|
||||
|
||||
lldb::FormatCategorySP category;
|
||||
Debugger::Formatting::Categories::Get(ConstString(m_options.m_category), category);
|
||||
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
const char* typeA = command.GetArgumentAtIndex(i);
|
||||
ConstString typeCS(typeA);
|
||||
if (typeCS)
|
||||
category->Filter()->Add(typeCS.GetCString(), entry);
|
||||
else
|
||||
{
|
||||
result.AppendError("empty typenames not allowed");
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
bool
|
||||
CommandObjectTypeSynthAdd::Execute_HandwritePython (Args& command, CommandReturnObject &result)
|
||||
{
|
||||
SynthAddOptions *options = new SynthAddOptions ( m_options.m_skip_pointers,
|
||||
m_options.m_skip_references,
|
||||
m_options.m_cascade,
|
||||
m_options.m_regex,
|
||||
m_options.m_category);
|
||||
|
||||
bool
|
||||
Execute_PythonClass (Args& command, CommandReturnObject &result)
|
||||
{
|
||||
const size_t argc = command.GetArgumentCount();
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_options.m_class_name.empty() && !m_options.m_input_python)
|
||||
{
|
||||
result.AppendErrorWithFormat ("%s needs either a Python class name or -P to directly input Python code.\n", m_cmd_name.c_str());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
SyntheticChildrenSP entry;
|
||||
|
||||
SyntheticScriptProvider* impl = new SyntheticScriptProvider(m_options.m_cascade,
|
||||
m_options.m_skip_pointers,
|
||||
m_options.m_skip_references,
|
||||
m_options.m_class_name);
|
||||
|
||||
entry.reset(impl);
|
||||
|
||||
// now I have a valid provider, let's add it to every type
|
||||
|
||||
lldb::FormatCategorySP category;
|
||||
Debugger::Formatting::Categories::Get(ConstString(m_options.m_category), category);
|
||||
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
const char* typeA = command.GetArgumentAtIndex(i);
|
||||
ConstString typeCS(typeA);
|
||||
if (typeCS)
|
||||
category->Filter()->Add(typeCS.GetCString(), entry);
|
||||
else
|
||||
{
|
||||
result.AppendError("empty typenames not allowed");
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
const size_t argc = command.GetArgumentCount();
|
||||
|
||||
public:
|
||||
|
||||
CommandObjectTypeSynthAdd (CommandInterpreter &interpreter) :
|
||||
CommandObject (interpreter,
|
||||
"type synth add",
|
||||
"Add a new synthetic provider for a type.",
|
||||
NULL), m_options (interpreter)
|
||||
{
|
||||
CommandArgumentEntry type_arg;
|
||||
CommandArgumentData type_style_arg;
|
||||
|
||||
type_style_arg.arg_type = eArgTypeName;
|
||||
type_style_arg.arg_repetition = eArgRepeatPlus;
|
||||
|
||||
type_arg.push_back (type_style_arg);
|
||||
|
||||
m_arguments.push_back (type_arg);
|
||||
|
||||
}
|
||||
|
||||
~CommandObjectTypeSynthAdd ()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Execute (Args& command, CommandReturnObject &result)
|
||||
{
|
||||
if (m_options.handwrite_python)
|
||||
return Execute_HandwritePython(command, result);
|
||||
else if (m_options.is_class_based)
|
||||
return Execute_PythonClass(command, result);
|
||||
else if (m_options.has_child_list)
|
||||
return Execute_ChildrenList(command, result);
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
const char* typeA = command.GetArgumentAtIndex(i);
|
||||
if (typeA && *typeA)
|
||||
options->m_target_types << typeA;
|
||||
else
|
||||
{
|
||||
result.AppendError("must either provide a children list, a Python class name, or use -P and type a Python class line-by-line");
|
||||
result.AppendError("empty typenames not allowed");
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CollectPythonScript(options,result);
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
bool
|
||||
CommandObjectTypeSynthAdd::Execute_ChildrenList (Args& command, CommandReturnObject &result)
|
||||
{
|
||||
const size_t argc = command.GetArgumentCount();
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_options.m_expr_paths.size() == 0)
|
||||
{
|
||||
result.AppendErrorWithFormat ("%s needs one or more children.\n", m_cmd_name.c_str());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
SyntheticChildrenSP entry;
|
||||
|
||||
SyntheticFilter* impl = new SyntheticFilter(m_options.m_cascade,
|
||||
m_options.m_skip_pointers,
|
||||
m_options.m_skip_references);
|
||||
|
||||
entry.reset(impl);
|
||||
|
||||
// go through the expression paths
|
||||
CommandOptions::ExpressionPathsIterator begin, end = m_options.m_expr_paths.end();
|
||||
|
||||
for (begin = m_options.m_expr_paths.begin(); begin != end; begin++)
|
||||
impl->AddExpressionPath(*begin);
|
||||
|
||||
|
||||
// now I have a valid provider, let's add it to every type
|
||||
|
||||
lldb::FormatCategorySP category;
|
||||
Debugger::Formatting::Categories::Get(ConstString(m_options.m_category), category);
|
||||
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
const char* typeA = command.GetArgumentAtIndex(i);
|
||||
ConstString typeCS(typeA);
|
||||
if (typeCS)
|
||||
AddSynth(typeCS,
|
||||
entry,
|
||||
m_options.m_regex ? eRegexSynth : eRegularSynth,
|
||||
m_options.m_category,
|
||||
NULL);
|
||||
else
|
||||
{
|
||||
result.AppendError("empty typenames not allowed");
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
bool
|
||||
CommandObjectTypeSynthAdd::Execute_PythonClass (Args& command, CommandReturnObject &result)
|
||||
{
|
||||
const size_t argc = command.GetArgumentCount();
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_options.m_class_name.empty() && !m_options.m_input_python)
|
||||
{
|
||||
result.AppendErrorWithFormat ("%s needs either a Python class name or -P to directly input Python code.\n", m_cmd_name.c_str());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
SyntheticChildrenSP entry;
|
||||
|
||||
SyntheticScriptProvider* impl = new SyntheticScriptProvider(m_options.m_cascade,
|
||||
m_options.m_skip_pointers,
|
||||
m_options.m_skip_references,
|
||||
m_options.m_class_name);
|
||||
|
||||
entry.reset(impl);
|
||||
|
||||
// now I have a valid provider, let's add it to every type
|
||||
|
||||
lldb::FormatCategorySP category;
|
||||
Debugger::Formatting::Categories::Get(ConstString(m_options.m_category), category);
|
||||
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
const char* typeA = command.GetArgumentAtIndex(i);
|
||||
ConstString typeCS(typeA);
|
||||
if (typeCS)
|
||||
AddSynth(typeCS,
|
||||
entry,
|
||||
m_options.m_regex ? eRegexSynth : eRegularSynth,
|
||||
m_options.m_category,
|
||||
NULL);
|
||||
else
|
||||
{
|
||||
result.AppendError("empty typenames not allowed");
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
CommandObjectTypeSynthAdd::CommandObjectTypeSynthAdd (CommandInterpreter &interpreter) :
|
||||
CommandObject (interpreter,
|
||||
"type synth add",
|
||||
"Add a new synthetic provider for a type.",
|
||||
NULL), m_options (interpreter)
|
||||
{
|
||||
CommandArgumentEntry type_arg;
|
||||
CommandArgumentData type_style_arg;
|
||||
|
||||
type_style_arg.arg_type = eArgTypeName;
|
||||
type_style_arg.arg_repetition = eArgRepeatPlus;
|
||||
|
||||
type_arg.push_back (type_style_arg);
|
||||
|
||||
m_arguments.push_back (type_arg);
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
CommandObjectTypeSynthAdd::AddSynth(const ConstString& type_name,
|
||||
SyntheticChildrenSP entry,
|
||||
SynthFormatType type,
|
||||
const char* category_name,
|
||||
Error* error)
|
||||
{
|
||||
lldb::FormatCategorySP category;
|
||||
Debugger::Formatting::Categories::Get(ConstString(category_name), category);
|
||||
|
||||
if (type == eRegexSynth)
|
||||
{
|
||||
RegularExpressionSP typeRX(new RegularExpression());
|
||||
if (!typeRX->Compile(type_name.GetCString()))
|
||||
{
|
||||
if (error)
|
||||
error->SetErrorString("regex format error (maybe this is not really a regex?)");
|
||||
return false;
|
||||
}
|
||||
|
||||
category->RegexFilter()->Delete(type_name.GetCString());
|
||||
category->RegexFilter()->Add(typeRX, entry);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
category->Filter()->Add(type_name.GetCString(), entry);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CommandObjectTypeSynthAdd::Execute (Args& command, CommandReturnObject &result)
|
||||
{
|
||||
if (m_options.handwrite_python)
|
||||
return Execute_HandwritePython(command, result);
|
||||
else if (m_options.is_class_based)
|
||||
return Execute_PythonClass(command, result);
|
||||
else if (m_options.has_child_list)
|
||||
return Execute_ChildrenList(command, result);
|
||||
else
|
||||
{
|
||||
result.AppendError("must either provide a children list, a Python class name, or use -P and type a Python class line-by-line");
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
OptionDefinition
|
||||
CommandObjectTypeSynthAdd::CommandOptions::g_option_table[] =
|
||||
|
@ -2841,6 +2785,7 @@ CommandObjectTypeSynthAdd::CommandOptions::g_option_table[] =
|
|||
{ LLDB_OPT_SET_1, false, "child", 'c', required_argument, NULL, 0, eArgTypeName, "Include this expression path in the synthetic view."},
|
||||
{ LLDB_OPT_SET_2, false, "python-class", 'l', required_argument, NULL, 0, eArgTypeName, "Use this Python class to produce synthetic children."},
|
||||
{ LLDB_OPT_SET_3, false, "input-python", 'P', no_argument, NULL, 0, eArgTypeNone, "Type Python code to generate a class that provides synthetic children."},
|
||||
{ LLDB_OPT_SET_ALL, false, "regex", 'x', no_argument, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
|
||||
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
|
||||
};
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ public:
|
|||
bool m_skip_pointers;
|
||||
bool m_skip_references;
|
||||
bool m_cascade;
|
||||
bool m_regex;
|
||||
StringList m_user_source;
|
||||
StringList m_target_types;
|
||||
|
||||
|
@ -86,10 +87,12 @@ public:
|
|||
SynthAddOptions(bool sptr,
|
||||
bool sref,
|
||||
bool casc,
|
||||
bool regx,
|
||||
const char* catg) :
|
||||
m_skip_pointers(sptr),
|
||||
m_skip_references(sref),
|
||||
m_cascade(casc),
|
||||
m_regex(regx),
|
||||
m_user_source(),
|
||||
m_target_types(),
|
||||
m_category(catg)
|
||||
|
@ -203,7 +206,157 @@ public:
|
|||
const char* category,
|
||||
Error* error = NULL);
|
||||
};
|
||||
|
||||
|
||||
class CommandObjectTypeSynthAdd : public CommandObject
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
class CommandOptions : public Options
|
||||
{
|
||||
typedef std::vector<std::string> option_vector;
|
||||
public:
|
||||
|
||||
CommandOptions (CommandInterpreter &interpreter) :
|
||||
Options (interpreter)
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
~CommandOptions (){}
|
||||
|
||||
virtual Error
|
||||
SetOptionValue (uint32_t option_idx, const char *option_arg)
|
||||
{
|
||||
Error error;
|
||||
char short_option = (char) m_getopt_table[option_idx].val;
|
||||
bool success;
|
||||
|
||||
switch (short_option)
|
||||
{
|
||||
case 'C':
|
||||
m_cascade = Args::StringToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat("Invalid value for cascade: %s.\n", option_arg);
|
||||
break;
|
||||
case 'c':
|
||||
m_expr_paths.push_back(option_arg);
|
||||
has_child_list = true;
|
||||
break;
|
||||
case 'P':
|
||||
handwrite_python = true;
|
||||
break;
|
||||
case 'l':
|
||||
m_class_name = std::string(option_arg);
|
||||
is_class_based = true;
|
||||
break;
|
||||
case 'p':
|
||||
m_skip_pointers = true;
|
||||
break;
|
||||
case 'r':
|
||||
m_skip_references = true;
|
||||
break;
|
||||
case 'w':
|
||||
m_category = ConstString(option_arg).GetCString();
|
||||
break;
|
||||
case 'x':
|
||||
m_regex = true;
|
||||
break;
|
||||
default:
|
||||
error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void
|
||||
OptionParsingStarting ()
|
||||
{
|
||||
m_cascade = true;
|
||||
m_class_name = "";
|
||||
m_skip_pointers = false;
|
||||
m_skip_references = false;
|
||||
m_category = NULL;
|
||||
m_expr_paths.clear();
|
||||
is_class_based = false;
|
||||
handwrite_python = false;
|
||||
has_child_list = false;
|
||||
m_regex = false;
|
||||
}
|
||||
|
||||
const OptionDefinition*
|
||||
GetDefinitions ()
|
||||
{
|
||||
return g_option_table;
|
||||
}
|
||||
|
||||
// Options table: Required for subclasses of Options.
|
||||
|
||||
static OptionDefinition g_option_table[];
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
|
||||
bool m_cascade;
|
||||
bool m_skip_references;
|
||||
bool m_skip_pointers;
|
||||
std::string m_class_name;
|
||||
bool m_input_python;
|
||||
option_vector m_expr_paths;
|
||||
const char* m_category;
|
||||
|
||||
bool is_class_based;
|
||||
|
||||
bool handwrite_python;
|
||||
|
||||
bool has_child_list;
|
||||
|
||||
bool m_regex;
|
||||
|
||||
typedef option_vector::iterator ExpressionPathsIterator;
|
||||
};
|
||||
|
||||
CommandOptions m_options;
|
||||
|
||||
virtual Options *
|
||||
GetOptions ()
|
||||
{
|
||||
return &m_options;
|
||||
}
|
||||
|
||||
void
|
||||
CollectPythonScript (SynthAddOptions *options,
|
||||
CommandReturnObject &result);
|
||||
bool
|
||||
Execute_HandwritePython (Args& command, CommandReturnObject &result);
|
||||
bool
|
||||
Execute_ChildrenList (Args& command, CommandReturnObject &result);
|
||||
bool
|
||||
Execute_PythonClass (Args& command, CommandReturnObject &result);
|
||||
bool
|
||||
Execute (Args& command, CommandReturnObject &result);
|
||||
|
||||
public:
|
||||
|
||||
enum SynthFormatType
|
||||
{
|
||||
eRegularSynth,
|
||||
eRegexSynth,
|
||||
};
|
||||
|
||||
CommandObjectTypeSynthAdd (CommandInterpreter &interpreter);
|
||||
|
||||
~CommandObjectTypeSynthAdd ()
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
AddSynth(const ConstString& type_name,
|
||||
lldb::SyntheticChildrenSP entry,
|
||||
SynthFormatType type,
|
||||
const char* category_name,
|
||||
Error* error);
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
|
|
|
@ -300,13 +300,14 @@ class DataFormatterTestCase(TestBase):
|
|||
'[3] = \"!!!\"'])
|
||||
|
||||
# now std::map<K,V>
|
||||
# also take a chance to test regex synth here
|
||||
|
||||
self.runCmd("n")
|
||||
self.runCmd("frame variable ii -T")
|
||||
|
||||
self.runCmd("script from StdMapSynthProvider import *")
|
||||
self.runCmd("type summary add std::intint_map intint_map -f \"map has ${svar%#} items\" -e")
|
||||
self.runCmd("type synth add std::intint_map intint_map -l StdMapSynthProvider")
|
||||
self.runCmd("type summary add -x \"std::map<\" -f \"map has ${svar%#} items\" -e")
|
||||
self.runCmd("type synth add -x \"std::map<\" -l StdMapSynthProvider")
|
||||
|
||||
|
||||
self.expect('frame variable ii',
|
||||
|
@ -356,8 +357,8 @@ class DataFormatterTestCase(TestBase):
|
|||
self.runCmd("n")
|
||||
self.runCmd("frame variable si -T")
|
||||
|
||||
self.runCmd("type summary add std::strint_map strint_map -f \"map has ${svar%#} items\" -e")
|
||||
self.runCmd("type synth add std::strint_map strint_map -l StdMapSynthProvider")
|
||||
#self.runCmd("type summary add std::strint_map strint_map -f \"map has ${svar%#} items\" -e")
|
||||
#self.runCmd("type synth add std::strint_map strint_map -l StdMapSynthProvider")
|
||||
|
||||
self.expect('frame variable si',
|
||||
substrs = ['map has 0 items',
|
||||
|
@ -400,8 +401,8 @@ class DataFormatterTestCase(TestBase):
|
|||
self.runCmd("n")
|
||||
self.runCmd("frame variable is -T")
|
||||
|
||||
self.runCmd("type summary add std::intstr_map intstr_map -f \"map has ${svar%#} items\" -e")
|
||||
self.runCmd("type synth add std::intstr_map intstr_map -l StdMapSynthProvider")
|
||||
#self.runCmd("type summary add std::intstr_map intstr_map -f \"map has ${svar%#} items\" -e")
|
||||
#self.runCmd("type synth add std::intstr_map intstr_map -l StdMapSynthProvider")
|
||||
|
||||
self.expect('frame variable is',
|
||||
substrs = ['map has 0 items',
|
||||
|
@ -433,8 +434,8 @@ class DataFormatterTestCase(TestBase):
|
|||
self.runCmd("n")
|
||||
self.runCmd("frame variable ss -T")
|
||||
|
||||
self.runCmd("type summary add std::strstr_map strstr_map -f \"map has ${svar%#} items\" -e")
|
||||
self.runCmd("type synth add std::strstr_map strstr_map -l StdMapSynthProvider")
|
||||
#self.runCmd("type summary add std::strstr_map strstr_map -f \"map has ${svar%#} items\" -e")
|
||||
#self.runCmd("type synth add std::strstr_map strstr_map -l StdMapSynthProvider")
|
||||
|
||||
self.expect('frame variable ss',
|
||||
substrs = ['map has 0 items',
|
||||
|
|
|
@ -8,10 +8,10 @@ typedef std::vector<std::string> string_vect;
|
|||
typedef std::list<int> int_list;
|
||||
typedef std::list<std::string> string_list;
|
||||
|
||||
typedef std::map<int, int> intint_map;
|
||||
typedef std::map<std::string, int> strint_map;
|
||||
typedef std::map<int, std::string> intstr_map;
|
||||
typedef std::map<std::string, std::string> strstr_map;
|
||||
#define intint_map std::map<int, int>
|
||||
#define strint_map std::map<std::string, int>
|
||||
#define intstr_map std::map<int, std::string>
|
||||
#define strstr_map std::map<std::string, std::string>
|
||||
|
||||
struct foo
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue