diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index b06db9a090f6..7e374cbb2c82 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -505,6 +505,9 @@ public:
static bool
GetSummaryFormat(ValueObject& vobj,
lldb::SummaryFormatSP& entry);
+ static bool
+ GetSyntheticFilter(ValueObject& vobj,
+ lldb::SyntheticFilterSP& entry);
class NamedSummaryFormats
{
diff --git a/lldb/include/lldb/Core/FormatClasses.h b/lldb/include/lldb/Core/FormatClasses.h
index a6002abb54e9..c67372138a7b 100644
--- a/lldb/include/lldb/Core/FormatClasses.h
+++ b/lldb/include/lldb/Core/FormatClasses.h
@@ -17,6 +17,7 @@
// C++ Includes
#include
+#include
// Other libraries and framework includes
@@ -55,23 +56,23 @@ struct ValueFormat
}
bool
- Cascades()
+ Cascades() const
{
return m_cascades;
}
bool
- SkipsPointers()
+ SkipsPointers() const
{
return m_skip_pointers;
}
bool
- SkipsReferences()
+ SkipsReferences() const
{
return m_skip_references;
}
lldb::Format
- GetFormat()
+ GetFormat() const
{
return m_format;
}
@@ -80,6 +81,57 @@ struct ValueFormat
FormatObject(lldb::ValueObjectSP object);
};
+
+struct SyntheticFilter
+{
+ bool m_cascades;
+ bool m_skip_pointers;
+ bool m_skip_references;
+ std::vector m_expression_paths;
+
+ SyntheticFilter(bool casc = false,
+ bool skipptr = false,
+ bool skipref = false) :
+ m_cascades(casc),
+ m_skip_pointers(skipptr),
+ m_skip_references(skipref),
+ m_expression_paths()
+ {
+ }
+
+ void
+ AddExpressionPath(std::string path)
+ {
+ bool need_add_dot = true;
+ if (path[0] == '.' ||
+ (path[0] == '-' && path[1] == '>') ||
+ path[0] == '[')
+ need_add_dot = false;
+ // add a '.' symbol to help forgetful users
+ if(!need_add_dot)
+ m_expression_paths.push_back(path);
+ else
+ m_expression_paths.push_back(std::string(".") + path);
+ }
+
+ int
+ GetCount() const
+ {
+ return m_expression_paths.size();
+ }
+
+ const std::string&
+ GetExpressionPathAtIndex(int i) const
+ {
+ return m_expression_paths[i];
+ }
+
+ std::string
+ GetDescription();
+
+ typedef lldb::SharedPtr::Type SharedPointer;
+ typedef bool(*SyntheticFilterCallback)(void*, const char*, const SyntheticFilter::SharedPointer&);
+};
struct SummaryFormat
{
@@ -106,17 +158,17 @@ struct SummaryFormat
}
bool
- Cascades()
+ Cascades() const
{
return m_cascades;
}
bool
- SkipsPointers()
+ SkipsPointers() const
{
return m_skip_pointers;
}
bool
- SkipsReferences()
+ SkipsReferences() const
{
return m_skip_references;
}
@@ -174,7 +226,7 @@ struct StringSummaryFormat : public SummaryFormat
}
std::string
- GetFormat()
+ GetFormat() const
{
return m_format;
}
@@ -213,13 +265,13 @@ struct ScriptSummaryFormat : public SummaryFormat
}
std::string
- GetFunctionName()
+ GetFunctionName() const
{
return m_function_name;
}
std::string
- GetPythonScript()
+ GetPythonScript() const
{
return m_python_script;
}
diff --git a/lldb/include/lldb/Core/FormatManager.h b/lldb/include/lldb/Core/FormatManager.h
index 1a6f49859544..1dd97b04d263 100644
--- a/lldb/include/lldb/Core/FormatManager.h
+++ b/lldb/include/lldb/Core/FormatManager.h
@@ -415,12 +415,15 @@ class FormatCategory
private:
typedef FormatNavigator SummaryNavigator;
typedef FormatNavigator RegexSummaryNavigator;
+ typedef FormatNavigator FilterNavigator;
typedef SummaryNavigator::MapType SummaryMap;
typedef RegexSummaryNavigator::MapType RegexSummaryMap;
+ typedef FilterNavigator::MapType FilterMap;
SummaryNavigator::SharedPointer m_summary_nav;
RegexSummaryNavigator::SharedPointer m_regex_summary_nav;
+ FilterNavigator::SharedPointer m_filter_nav;
bool m_enabled;
@@ -428,6 +431,8 @@ private:
Mutex m_mutex;
+ std::string m_name;
+
void
Enable(bool value = true)
{
@@ -449,13 +454,17 @@ public:
typedef SummaryNavigator::SharedPointer SummaryNavigatorSP;
typedef RegexSummaryNavigator::SharedPointer RegexSummaryNavigatorSP;
+ typedef FilterNavigator::SharedPointer FilterNavigatorSP;
- FormatCategory(IFormatChangeListener* clist) :
+ FormatCategory(IFormatChangeListener* clist,
+ std::string name) :
m_summary_nav(new SummaryNavigator(clist)),
m_regex_summary_nav(new RegexSummaryNavigator(clist)),
+ m_filter_nav(new FilterNavigator(clist)),
m_enabled(false),
m_change_listener(clist),
- m_mutex(Mutex::eMutexTypeRecursive)
+ m_mutex(Mutex::eMutexTypeRecursive),
+ m_name(name)
{}
SummaryNavigatorSP
@@ -470,6 +479,12 @@ public:
return RegexSummaryNavigatorSP(m_regex_summary_nav);
}
+ FilterNavigatorSP
+ Filter()
+ {
+ return FilterNavigatorSP(m_filter_nav);
+ }
+
bool
IsEnabled() const
{
@@ -491,15 +506,27 @@ public:
return regex;
}
+ bool
+ Get(ValueObject& vobj,
+ lldb::SyntheticFilterSP& entry,
+ uint32_t* reason = NULL)
+ {
+ if (!IsEnabled())
+ return false;
+ return (Filter()->Get(vobj, entry, reason));
+ }
+
+ // just a shortcut for Summary()->Clear; RegexSummary()->Clear()
void
- Clear()
+ ClearSummaries()
{
m_summary_nav->Clear();
m_regex_summary_nav->Clear();
}
+ // just a shortcut for (Summary()->Delete(name) || RegexSummary()->Delete(name))
bool
- Delete(const char* name)
+ DeleteSummaries(const char* name)
{
bool del_sum = m_summary_nav->Delete(name);
bool del_rex = m_regex_summary_nav->Delete(name);
@@ -513,6 +540,12 @@ public:
return Summary()->GetCount() + RegexSummary()->GetCount();
}
+ std::string
+ GetName()
+ {
+ return m_name;
+ }
+
typedef lldb::SharedPtr::Type SharedPointer;
};
@@ -648,23 +681,6 @@ public:
return true;
}
- class match_category_to_name
- {
- private:
- FormatCategory* addr;
- public:
-
- match_category_to_name(FormatCategory* ptr) : addr(ptr)
- {}
-
- bool operator()(std::pair map_entry)
- {
- if (addr == map_entry.second.get())
- return true;
- return false;
- }
- };
-
void
LoopThrough(CallbackType callback, void* param)
{
@@ -678,13 +694,7 @@ public:
for (begin = m_active_categories.begin(); begin != end; begin++)
{
FormatCategory::SharedPointer category = *begin;
- const char* type;
- MapIterator type_position =
- std::find_if(m_map.begin(),m_map.end(),match_category_to_name(category.get()));
- if (type_position != m_map.end())
- type = type_position->first;
- else
- continue;
+ const char* type = category->GetName().c_str();
if (!callback(param, type, category))
break;
}
@@ -741,6 +751,38 @@ public:
}
return !first;
}
+
+ bool
+ Get(ValueObject& vobj,
+ lldb::SyntheticFilterSP& entry)
+ {
+ Mutex::Locker(m_map_mutex);
+
+ uint32_t reason_why;
+ bool first = true;
+
+ ActiveCategoriesIterator begin, end = m_active_categories.end();
+
+ for (begin = m_active_categories.begin(); begin != end; begin++)
+ {
+ FormatCategory::SharedPointer category = *begin;
+ lldb::SyntheticFilterSP current_format;
+ if (!category->Get(vobj, current_format, &reason_why))
+ continue;
+ if (reason_why == lldb::eFormatterDirectChoice)
+ {
+ entry = current_format;
+ return true;
+ }
+ else if (first)
+ {
+ entry = current_format;
+ first = false;
+ }
+ }
+ return !first;
+ }
+
};
@@ -856,7 +898,7 @@ public:
lldb::FormatCategorySP category;
if (m_categories_map.Get(category_name, category))
return category;
- Categories().Add(category_name,lldb::FormatCategorySP(new FormatCategory(this)));
+ Categories().Add(category_name,lldb::FormatCategorySP(new FormatCategory(this, category_name)));
return Category(category_name);
}
@@ -866,6 +908,12 @@ public:
{
return m_categories_map.Get(vobj, entry);
}
+ bool
+ Get(ValueObject& vobj,
+ lldb::SyntheticFilterSP& entry)
+ {
+ return m_categories_map.Get(vobj, entry);
+ }
static bool
GetFormatFromCString (const char *format_cstr,
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index 1c3eddc8b25d..8eb018e2113e 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -466,7 +466,7 @@ public:
const ConstString &
GetName() const;
- lldb::ValueObjectSP
+ virtual lldb::ValueObjectSP
GetChildAtIndex (uint32_t idx, bool can_create);
virtual lldb::ValueObjectSP
@@ -545,9 +545,15 @@ public:
lldb::ValueObjectSP
GetSyntheticBitFieldChild (uint32_t from, uint32_t to, bool can_create);
+ lldb::ValueObjectSP
+ GetSyntheticExpressionPathChild(const char* expression, bool can_create);
+
lldb::ValueObjectSP
GetDynamicValue (lldb::DynamicValueType valueType);
+ lldb::ValueObjectSP
+ GetSyntheticValue (lldb::SyntheticValueType use_synthetic);
+
virtual lldb::ValueObjectSP
CreateConstantValue (const ConstString &name);
@@ -592,6 +598,7 @@ public:
bool show_location,
bool use_objc,
lldb::DynamicValueType use_dynamic,
+ bool use_synthetic,
bool scope_already_checked,
bool flat_output,
uint32_t omit_summary_depth);
@@ -727,6 +734,7 @@ protected:
std::vector m_children;
std::map m_synthetic_children;
ValueObject *m_dynamic_value;
+ ValueObject *m_synthetic_value;
lldb::ValueObjectSP m_addr_of_valobj_sp; // We have to hold onto a shared pointer to this one because it is created
// as an independent ValueObjectConstResult, which isn't managed by us.
ValueObject *m_deref_valobj;
@@ -736,6 +744,7 @@ protected:
lldb::SummaryFormatSP m_last_summary_format;
lldb::SummaryFormatSP m_forced_summary_format;
lldb::ValueFormatSP m_last_value_format;
+ lldb::SyntheticFilterSP m_last_synthetic_filter;
lldb::user_id_t m_user_id_of_forced_summary;
bool m_value_is_valid:1,
m_value_did_change:1,
@@ -744,7 +753,8 @@ protected:
m_pointers_point_to_load_addrs:1,
m_is_deref_of_parent:1,
m_is_array_item_for_pointer:1,
- m_is_bitfield_for_scalar:1;
+ m_is_bitfield_for_scalar:1,
+ m_is_expression_path_child:1;
// used to prevent endless looping into GetpPrintableRepresentation()
uint32_t m_dump_printable_counter;
@@ -782,6 +792,9 @@ protected:
virtual void
CalculateDynamicValue (lldb::DynamicValueType use_dynamic);
+ virtual void
+ CalculateSyntheticValue (lldb::SyntheticValueType use_synthetic);
+
// Should only be called by ValueObject::GetChildAtIndex()
// Returns a ValueObject managed by this ValueObject's manager.
virtual ValueObject *
diff --git a/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h b/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h
new file mode 100644
index 000000000000..571fba37dc06
--- /dev/null
+++ b/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h
@@ -0,0 +1,122 @@
+//===-- ValueObjectSyntheticFilter.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ValueObjectSyntheticFilter_h_
+#define liblldb_ValueObjectSyntheticFilter_h_
+
+// C Includes
+// C++ Includes
+#include
+#include
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObject.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A ValueObject that represents memory at a given address, viewed as some
+// set lldb type.
+//----------------------------------------------------------------------
+class ValueObjectSyntheticFilter : public ValueObject
+{
+public:
+ virtual
+ ~ValueObjectSyntheticFilter();
+
+ virtual size_t
+ GetByteSize();
+
+ virtual clang::ASTContext *
+ GetClangAST ();
+
+ virtual lldb::clang_type_t
+ GetClangType ();
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual uint32_t
+ CalculateNumChildren();
+
+ virtual lldb::ValueType
+ GetValueType() const;
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (uint32_t idx, bool can_create);
+
+ virtual lldb::ValueObjectSP
+ GetChildMemberWithName (const ConstString &name, bool can_create);
+
+ virtual uint32_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual bool
+ IsInScope ();
+
+ virtual bool
+ IsDynamic ()
+ {
+ if (m_parent)
+ return m_parent->IsDynamic();
+ else
+ return false;
+ }
+
+ virtual ValueObject *
+ GetParent()
+ {
+ if (m_parent)
+ return m_parent->GetParent();
+ else
+ return NULL;
+ }
+
+ virtual const ValueObject *
+ GetParent() const
+ {
+ if (m_parent)
+ return m_parent->GetParent();
+ else
+ return NULL;
+ }
+
+ void
+ SetOwningSP (lldb::ValueObjectSP &owning_sp)
+ {
+ if (m_owning_valobj_sp == owning_sp)
+ return;
+
+ assert (m_owning_valobj_sp.get() == NULL);
+ m_owning_valobj_sp = owning_sp;
+ }
+
+protected:
+ virtual bool
+ UpdateValue ();
+
+ Address m_address; ///< The variable that this value object is based upon
+ lldb::TypeSP m_type_sp;
+ lldb::ValueObjectSP m_owning_valobj_sp;
+ lldb::SyntheticValueType m_use_synthetic;
+ lldb::SyntheticFilterSP m_synth_filter;
+
+private:
+ friend class ValueObject;
+ ValueObjectSyntheticFilter (ValueObject &parent, lldb::SyntheticFilterSP filter);
+
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectSyntheticFilter);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectSyntheticFilter_h_
diff --git a/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h b/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h
index 8237621abcd7..c714525c366d 100644
--- a/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h
+++ b/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h
@@ -54,6 +54,7 @@ public:
uint32_t max_depth;
uint32_t ptr_depth;
lldb::DynamicValueType use_dynamic;
+ bool use_synth;
};
} // namespace lldb_private
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index c934073aa21d..e7961c88c727 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -324,6 +324,12 @@ namespace lldb {
eDynamicDontRunTarget = 2
} DynamicValueType;
+ typedef enum SyntheticValueType
+ {
+ eNoSyntheticFilter = 0,
+ eUseSyntheticFilter = 1
+ } SyntheticValueType;
+
typedef enum AccessType
{
eAccessNone,
diff --git a/lldb/include/lldb/lldb-forward-rtti.h b/lldb/include/lldb/lldb-forward-rtti.h
index e07771a8cb26..faedfe6a47cd 100644
--- a/lldb/include/lldb/lldb-forward-rtti.h
+++ b/lldb/include/lldb/lldb-forward-rtti.h
@@ -67,6 +67,7 @@ namespace lldb {
typedef SharedPtr::Type SummaryFormatSP;
typedef SharedPtr::Type SymbolFileSP;
typedef SharedPtr::Type SymbolContextSpecifierSP;
+ typedef SharedPtr::Type SyntheticFilterSP;
typedef SharedPtr::Type TargetSP;
typedef SharedPtr::Type ThreadSP;
typedef SharedPtr::Type ThreadPlanSP;
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index 4e4938bca7c0..412d9de8e10c 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -144,6 +144,7 @@ class SymbolContextSpecifier;
class SymbolFile;
class SymbolVendor;
class Symtab;
+class SyntheticFilter;
class Target;
class TargetList;
class Thread;
diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj
index a319f6c61bb8..18c9a3fe74c4 100644
--- a/lldb/lldb.xcodeproj/project.pbxproj
+++ b/lldb/lldb.xcodeproj/project.pbxproj
@@ -419,6 +419,7 @@
94611EB213CCA4A4003A22AF /* RefCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94611EB113CCA4A4003A22AF /* RefCounter.cpp */; };
9463D4CD13B1798800C230D4 /* CommandObjectType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9463D4CC13B1798800C230D4 /* CommandObjectType.cpp */; };
9467E65213C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9467E65113C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp */; };
+ 94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94B6E76113D88362005F417F /* ValueObjectSyntheticFilter.cpp */; };
9A19A6AF1163BBB200E0D453 /* SBValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A19A6A51163BB7E00E0D453 /* SBValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
9A19A6B01163BBB300E0D453 /* SBValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A19A6AD1163BB9800E0D453 /* SBValue.cpp */; };
9A22A161135E30370024DDC3 /* EmulateInstructionARM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A22A15D135E30370024DDC3 /* EmulateInstructionARM.cpp */; };
@@ -1218,6 +1219,8 @@
9467E65413C3D98900B3B6F3 /* TypeHierarchyNavigator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TypeHierarchyNavigator.h; path = include/lldb/Symbol/TypeHierarchyNavigator.h; sourceTree = ""; };
94A9112B13D5DEF80046D8A6 /* FormatClasses.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FormatClasses.h; path = include/lldb/Core/FormatClasses.h; sourceTree = ""; };
94A9112D13D5DF210046D8A6 /* FormatClasses.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FormatClasses.cpp; path = source/Core/FormatClasses.cpp; sourceTree = ""; };
+ 94B6E76013D8833C005F417F /* ValueObjectSyntheticFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ValueObjectSyntheticFilter.h; path = include/lldb/Core/ValueObjectSyntheticFilter.h; sourceTree = ""; };
+ 94B6E76113D88362005F417F /* ValueObjectSyntheticFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectSyntheticFilter.cpp; path = source/Core/ValueObjectSyntheticFilter.cpp; sourceTree = ""; };
961FABB81235DE1600F93A47 /* FuncUnwinders.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FuncUnwinders.cpp; path = source/Symbol/FuncUnwinders.cpp; sourceTree = ""; };
961FABB91235DE1600F93A47 /* UnwindPlan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindPlan.cpp; path = source/Symbol/UnwindPlan.cpp; sourceTree = ""; };
961FABBA1235DE1600F93A47 /* UnwindTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindTable.cpp; path = source/Symbol/UnwindTable.cpp; sourceTree = ""; };
@@ -2079,6 +2082,8 @@
4CABA9DF134A8BCD00539BDD /* ValueObjectMemory.cpp */,
2643343A1110F63C00CDB6C6 /* ValueObjectRegister.h */,
264334381110F63100CDB6C6 /* ValueObjectRegister.cpp */,
+ 94B6E76013D8833C005F417F /* ValueObjectSyntheticFilter.h */,
+ 94B6E76113D88362005F417F /* ValueObjectSyntheticFilter.cpp */,
26BC7D8510F1B77400F91463 /* ValueObjectVariable.h */,
26BC7E9D10F1B85900F91463 /* ValueObjectVariable.cpp */,
26BC7D8610F1B77400F91463 /* VMRange.h */,
@@ -3361,6 +3366,7 @@
2676045A13D49D2300AB1B6A /* ProcessControl-mig.defs in Sources */,
26D7E45D13D5E30A007FD12B /* SocketAddress.cpp in Sources */,
B271B11413D6139300C3FEDB /* FormatClasses.cpp in Sources */,
+ 94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index 26eaaf32209e..2528f4c361f5 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -648,6 +648,8 @@ SBValue::GetDescription (SBStream &description)
lldb::DynamicValueType use_dynamic = eNoDynamicValues;
bool scope_already_checked = false;
bool flat_output = false;
+ bool use_synthetic = true;
+ uint32_t no_summary_depth = 0;
ValueObject::DumpValueObject (description.ref(),
m_opaque_sp.get(),
m_opaque_sp->GetName().GetCString(),
@@ -656,10 +658,11 @@ SBValue::GetDescription (SBStream &description)
max_depth,
show_types, show_location,
use_objc,
- use_dynamic,
+ use_dynamic,
+ use_synthetic,
scope_already_checked,
flat_output,
- 0);
+ no_summary_depth);
}
else
description.Printf ("No value");
diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp
index cab8ed549fce..6109b643fdcb 100644
--- a/lldb/source/Commands/CommandObjectExpression.cpp
+++ b/lldb/source/Commands/CommandObjectExpression.cpp
@@ -334,6 +334,7 @@ CommandObjectExpression::EvaluateExpression
false, // Show locations of variables, no since this is a host address which we don't care to see
m_options.print_object, // Print the objective C object?
use_dynamic,
+ true, // Use synthetic children if available
true, // Scope is already checked. Const results are always in scope.
false, // Don't flatten output
0); // Always use summaries (you might want an option --no-summary like there is for frame variable)
diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
index 12670a1e9e51..eedc0cc1ca02 100644
--- a/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -499,7 +499,8 @@ public:
m_varobj_options.show_types,
m_varobj_options.show_location,
m_varobj_options.use_objc,
- m_varobj_options.use_dynamic,
+ m_varobj_options.use_dynamic,
+ m_varobj_options.use_synth,
false,
m_varobj_options.flat_output,
m_varobj_options.no_summary_depth);
@@ -552,6 +553,7 @@ public:
m_varobj_options.show_location,
m_varobj_options.use_objc,
m_varobj_options.use_dynamic,
+ m_varobj_options.use_synth,
false,
m_varobj_options.flat_output,
m_varobj_options.no_summary_depth);
@@ -643,6 +645,7 @@ public:
m_varobj_options.show_location,
m_varobj_options.use_objc,
m_varobj_options.use_dynamic,
+ m_varobj_options.use_synth,
false,
m_varobj_options.flat_output,
m_varobj_options.no_summary_depth);
diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp
index e91490ccf273..2a2c936e3520 100644
--- a/lldb/source/Commands/CommandObjectMemory.cpp
+++ b/lldb/source/Commands/CommandObjectMemory.cpp
@@ -657,6 +657,7 @@ public:
m_varobj_options.show_location,
m_varobj_options.use_objc,
m_varobj_options.use_dynamic,
+ m_varobj_options.use_synth,
scope_already_checked,
m_varobj_options.flat_output,
0);
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 1af50f0b76e8..814a2ad3144d 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -488,6 +488,7 @@ public:
m_varobj_options.show_location,
m_varobj_options.use_objc,
m_varobj_options.use_dynamic,
+ m_varobj_options.use_synth,
false,
m_varobj_options.flat_output,
m_varobj_options.no_summary_depth);
diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp
index c7b74d7306ba..3a8b16cf352c 100644
--- a/lldb/source/Commands/CommandObjectType.cpp
+++ b/lldb/source/Commands/CommandObjectType.cpp
@@ -1226,7 +1226,7 @@ public:
lldb::FormatCategorySP category;
Debugger::Formatting::Categories::Get(ConstString(m_options.m_category), category);
- bool delete_category = category->Delete(typeCS.GetCString());
+ bool delete_category = category->DeleteSummaries(typeCS.GetCString());
bool delete_named = Debugger::Formatting::NamedSummaryFormats::Delete(typeCS);
if (delete_category || delete_named)
@@ -1359,7 +1359,7 @@ public:
}
else
Debugger::Formatting::Categories::Get(ConstString(NULL), category);
- category->Clear();
+ category->ClearSummaries();
}
Debugger::Formatting::NamedSummaryFormats::Clear();
@@ -1885,6 +1885,670 @@ public:
};
+//-------------------------------------------------------------------------
+// CommandObjectTypeSynthList
+//-------------------------------------------------------------------------
+
+bool CommandObjectTypeSynthList_LoopCallback(void* pt2self, const char* type, const SyntheticFilter::SharedPointer& entry);
+
+class CommandObjectTypeSynthList;
+
+struct CommandObjectTypeSynthList_LoopCallbackParam {
+ CommandObjectTypeSynthList* self;
+ CommandReturnObject* result;
+ RegularExpression* regex;
+ RegularExpression* cate_regex;
+ CommandObjectTypeSynthList_LoopCallbackParam(CommandObjectTypeSynthList* S, CommandReturnObject* R,
+ RegularExpression* X = NULL,
+ RegularExpression* CX = NULL) : self(S), result(R), regex(X), cate_regex(CX) {}
+};
+
+class CommandObjectTypeSynthList : public CommandObject
+{
+
+ class CommandOptions : public Options
+ {
+ 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;
+
+ switch (short_option)
+ {
+ case 'w':
+ m_category_regex = std::string(option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_category_regex = "";
+ }
+
+ 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.
+
+ std::string m_category_regex;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+public:
+ CommandObjectTypeSynthList (CommandInterpreter &interpreter) :
+ CommandObject (interpreter,
+ "type synth list",
+ "Show a list of current synthetic providers.",
+ NULL), m_options(interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatOptional;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+ }
+
+ ~CommandObjectTypeSynthList ()
+ {
+ }
+
+ bool
+ Execute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ CommandObjectTypeSynthList_LoopCallbackParam *param;
+ RegularExpression* cate_regex =
+ m_options.m_category_regex.empty() ? NULL :
+ new RegularExpression(m_options.m_category_regex.c_str());
+
+ if (argc == 1) {
+ RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
+ regex->Compile(command.GetArgumentAtIndex(0));
+ param = new CommandObjectTypeSynthList_LoopCallbackParam(this,&result,regex,cate_regex);
+ }
+ else
+ param = new CommandObjectTypeSynthList_LoopCallbackParam(this,&result,NULL,cate_regex);
+
+ Debugger::Formatting::Categories::LoopThrough(PerCategoryCallback,param);
+
+ if (cate_regex)
+ delete cate_regex;
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+private:
+
+ static bool
+ PerCategoryCallback(void* param_vp,
+ const char* cate_name,
+ const FormatCategory::SharedPointer& cate)
+ {
+
+ CommandObjectTypeSynthList_LoopCallbackParam* param =
+ (CommandObjectTypeSynthList_LoopCallbackParam*)param_vp;
+ CommandReturnObject* result = param->result;
+
+ // if the category is disabled or empty and there is no regex, just skip it
+ if ((cate->IsEnabled() == false || cate->Filter()->GetCount() == 0) && param->cate_regex == NULL)
+ return true;
+
+ // if we have a regex and this category does not match it, just skip it
+ if(param->cate_regex != NULL && param->cate_regex->Execute(cate_name) == false)
+ return true;
+
+ result->GetOutputStream().Printf("-----------------------\nCategory: %s (%s)\n-----------------------\n",
+ cate_name,
+ (cate->IsEnabled() ? "enabled" : "disabled"));
+
+ cate->Filter()->LoopThrough(CommandObjectTypeSynthList_LoopCallback, param_vp);
+
+ return true;
+ }
+
+ bool
+ LoopCallback (const char* type,
+ const SyntheticFilter::SharedPointer& entry,
+ RegularExpression* regex,
+ CommandReturnObject *result)
+ {
+ if (regex == NULL || regex->Execute(type))
+ result->GetOutputStream().Printf ("%s: %s\n", type, entry->GetDescription().c_str());
+ return true;
+ }
+
+ friend bool CommandObjectTypeSynthList_LoopCallback(void* pt2self, const char* type, const SyntheticFilter::SharedPointer& entry);
+};
+
+bool
+CommandObjectTypeSynthList_LoopCallback (void* pt2self,
+ const char* type,
+ const SyntheticFilter::SharedPointer& entry)
+{
+ CommandObjectTypeSynthList_LoopCallbackParam* param = (CommandObjectTypeSynthList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(type, entry, param->regex, param->result);
+}
+
+
+OptionDefinition
+CommandObjectTypeSynthList::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "category-regex", 'w', required_argument, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSynthDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeSynthDelete : public CommandObject
+{
+private:
+ class CommandOptions : public Options
+ {
+ 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;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_delete_all = 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_delete_all = false;
+ m_category = NULL;
+ }
+
+ 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_delete_all;
+ const char* m_category;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ static bool
+ PerCategoryCallback(void* param,
+ const char* cate_name,
+ const FormatCategory::SharedPointer& cate)
+ {
+ const char* name = (const char*)param;
+ cate->Filter()->Delete(name);
+ return true;
+ }
+
+public:
+ CommandObjectTypeSynthDelete (CommandInterpreter &interpreter) :
+ CommandObject (interpreter,
+ "type synth delete",
+ "Delete an existing 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 = eArgRepeatPlain;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeSynthDelete ()
+ {
+ }
+
+ bool
+ Execute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const char* typeA = command.GetArgumentAtIndex(0);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_delete_all)
+ {
+ Debugger::Formatting::Categories::LoopThrough(PerCategoryCallback, (void*)typeCS.GetCString());
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+
+ lldb::FormatCategorySP category;
+ Debugger::Formatting::Categories::Get(ConstString(m_options.m_category), category);
+
+ bool delete_category = category->Filter()->Delete(typeCS.GetCString());
+
+ if (delete_category)
+ {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no custom synthetic provider for %s.\n", typeA);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ }
+};
+
+OptionDefinition
+CommandObjectTypeSynthDelete::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "all", 'a', no_argument, NULL, 0, eArgTypeBoolean, "Delete from every category."},
+ { LLDB_OPT_SET_2, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Delete from given category."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSynthClear
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeSynthClear : public CommandObject
+{
+private:
+
+ class CommandOptions : public Options
+ {
+ 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;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_delete_all = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_delete_all = 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_delete_all;
+ bool m_delete_named;
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ static bool
+ PerCategoryCallback(void* param,
+ const char* cate_name,
+ const FormatCategory::SharedPointer& cate)
+ {
+ cate->Filter()->Clear();
+ return true;
+
+ }
+
+public:
+ CommandObjectTypeSynthClear (CommandInterpreter &interpreter) :
+ CommandObject (interpreter,
+ "type synth clear",
+ "Delete all existing synthetic providers.",
+ NULL), m_options(interpreter)
+ {
+ }
+
+ ~CommandObjectTypeSynthClear ()
+ {
+ }
+
+ bool
+ Execute (Args& command, CommandReturnObject &result)
+ {
+
+ if (m_options.m_delete_all)
+ Debugger::Formatting::Categories::LoopThrough(PerCategoryCallback, NULL);
+
+ else
+ {
+ lldb::FormatCategorySP category;
+ if (command.GetArgumentCount() > 0)
+ {
+ const char* cat_name = command.GetArgumentAtIndex(0);
+ ConstString cat_nameCS(cat_name);
+ Debugger::Formatting::Categories::Get(cat_nameCS, category);
+ }
+ else
+ Debugger::Formatting::Categories::Get(ConstString(NULL), category);
+ category->Filter()->Clear();
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+OptionDefinition
+CommandObjectTypeSynthClear::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "all", 'a', no_argument, NULL, 0, eArgTypeBoolean, "Clear every category."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSynthAdd
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeSynthAdd : public CommandObject
+{
+
+private:
+
+ class CommandOptions : public Options
+ {
+ typedef std::vector 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);
+ 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_expr_paths.clear();
+ m_skip_pointers = false;
+ m_skip_references = false;
+ m_category = NULL;
+ }
+
+ 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;
+ option_vector m_expr_paths;
+ const char* m_category;
+
+ typedef option_vector::iterator ExpressionPathsIterator;
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+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)
+ {
+ 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;
+ }
+
+ SyntheticFilterSP entry;
+
+ entry.reset(new SyntheticFilter(m_options.m_cascade,
+ m_options.m_skip_pointers,
+ m_options.m_skip_references));
+
+ // 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++)
+ entry->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();
+ }
+};
+
+OptionDefinition
+CommandObjectTypeSynthAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade to derived typedefs."},
+ { LLDB_OPT_SET_ALL, false, "child", 'c', required_argument, NULL, 0, eArgTypeName, "Include this expression path in the synthetic view."},
+ { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeBoolean, "Don't use this format for pointers-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "skip-references", 'r', no_argument, NULL, 0, eArgTypeBoolean, "Don't use this format for references-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
class CommandObjectTypeFormat : public CommandObjectMultiword
{
public:
@@ -1906,6 +2570,27 @@ public:
}
};
+class CommandObjectTypeSynth : public CommandObjectMultiword
+{
+public:
+ CommandObjectTypeSynth (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "type synth",
+ "A set of commands for operating on synthetic type representations",
+ "type synth [] ")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeSynthAdd (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeSynthClear (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSynthDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeSynthList (interpreter)));
+ }
+
+
+ ~CommandObjectTypeSynth ()
+ {
+ }
+};
+
class CommandObjectTypeCategory : public CommandObjectMultiword
{
public:
@@ -1961,6 +2646,7 @@ CommandObjectType::CommandObjectType (CommandInterpreter &interpreter) :
LoadSubCommand ("category", CommandObjectSP (new CommandObjectTypeCategory (interpreter)));
LoadSubCommand ("format", CommandObjectSP (new CommandObjectTypeFormat (interpreter)));
LoadSubCommand ("summary", CommandObjectSP (new CommandObjectTypeSummary (interpreter)));
+ LoadSubCommand ("synth", CommandObjectSP (new CommandObjectTypeSynth (interpreter)));
}
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index cce768f86845..219fbfa89854 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -733,8 +733,12 @@ ScanFormatDescriptor(const char* var_name_begin,
// if this is a V, print the value using the default format
if (*format_name == 'V')
*val_obj_display = ValueObject::eDisplayValue;
+ // if this is an L, print the location of the value
if (*format_name == 'L')
*val_obj_display = ValueObject::eDisplayLocation;
+ // if this is an S, print the summary after all
+ if (*format_name == 'S')
+ *val_obj_display = ValueObject::eDisplaySummary;
}
// a good custom format tells us to print the value using it
else
@@ -1761,6 +1765,12 @@ Debugger::Formatting::GetSummaryFormat(ValueObject& vobj,
{
return GetFormatManager().Get(vobj, entry);
}
+bool
+Debugger::Formatting::GetSyntheticFilter(ValueObject& vobj,
+ lldb::SyntheticFilterSP& entry)
+{
+ return GetFormatManager().Get(vobj, entry);
+}
bool
Debugger::Formatting::Categories::Get(const ConstString &category, lldb::FormatCategorySP &entry)
@@ -1791,7 +1801,7 @@ Debugger::Formatting::Categories::Clear()
void
Debugger::Formatting::Categories::Clear(ConstString &category)
{
- GetFormatManager().Category(category.GetCString())->Clear();
+ GetFormatManager().Category(category.GetCString())->ClearSummaries();
}
void
diff --git a/lldb/source/Core/FormatClasses.cpp b/lldb/source/Core/FormatClasses.cpp
index 8ff237a603a3..f301a7bbc3a3 100644
--- a/lldb/source/Core/FormatClasses.cpp
+++ b/lldb/source/Core/FormatClasses.cpp
@@ -66,14 +66,15 @@ StringSummaryFormat::FormatObject(lldb::ValueObjectSP object)
if (m_show_members_oneliner)
{
- const uint32_t num_children = object->GetNumChildren();
+ ValueObjectSP synth_vobj = object->GetSyntheticValue(lldb::eUseSyntheticFilter);
+ const uint32_t num_children = synth_vobj->GetNumChildren();
if (num_children)
{
s.PutChar('(');
for (uint32_t idx=0; idxGetChildAtIndex(idx, true));
+ lldb::ValueObjectSP child_sp(synth_vobj->GetChildAtIndex(idx, true));
if (child_sp.get())
{
if (idx)
@@ -137,4 +138,21 @@ ScriptSummaryFormat::GetDescription()
}
-
+std::string
+SyntheticFilter::GetDescription()
+{
+ StreamString sstr;
+ sstr.Printf("%s%s%s {\n",
+ m_cascades ? "" : " (not cascading)",
+ m_skip_pointers ? " (skip pointers)" : "",
+ m_skip_references ? " (skip references)" : "");
+
+ for (int i = 0; i < GetCount(); i++)
+ {
+ sstr.Printf(" %s\n",
+ GetExpressionPathAtIndex(i).c_str());
+ }
+
+ sstr.Printf("}");
+ return sstr.GetString();
+}
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index 5721b40f548f..acc85df556ff 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -26,6 +26,7 @@
#include "lldb/Core/ValueObjectDynamicValue.h"
#include "lldb/Core/ValueObjectList.h"
#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Core/ValueObjectSyntheticFilter.h"
#include "lldb/Host/Endian.h"
@@ -70,12 +71,14 @@ ValueObject::ValueObject (ValueObject &parent) :
m_children (),
m_synthetic_children (),
m_dynamic_value (NULL),
+ m_synthetic_value(NULL),
m_deref_valobj(NULL),
m_format (eFormatDefault),
m_last_format_mgr_revision(0),
m_last_summary_format(),
m_forced_summary_format(),
m_last_value_format(),
+ m_last_synthetic_filter(),
m_user_id_of_forced_summary(0),
m_value_is_valid (false),
m_value_did_change (false),
@@ -85,6 +88,7 @@ ValueObject::ValueObject (ValueObject &parent) :
m_is_deref_of_parent (false),
m_is_array_item_for_pointer(false),
m_is_bitfield_for_scalar(false),
+ m_is_expression_path_child(false),
m_dump_printable_counter(0)
{
m_manager->ManageObject(this);
@@ -110,12 +114,14 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope) :
m_children (),
m_synthetic_children (),
m_dynamic_value (NULL),
+ m_synthetic_value(NULL),
m_deref_valobj(NULL),
m_format (eFormatDefault),
m_last_format_mgr_revision(0),
m_last_summary_format(),
m_forced_summary_format(),
m_last_value_format(),
+ m_last_synthetic_filter(),
m_user_id_of_forced_summary(0),
m_value_is_valid (false),
m_value_did_change (false),
@@ -125,6 +131,7 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope) :
m_is_deref_of_parent (false),
m_is_array_item_for_pointer(false),
m_is_bitfield_for_scalar(false),
+ m_is_expression_path_child(false),
m_dump_printable_counter(0)
{
m_manager = new ValueObjectManager();
@@ -209,14 +216,13 @@ ValueObject::UpdateFormatsIfNeeded()
if (m_last_summary_format.get())
m_last_summary_format.reset((StringSummaryFormat*)NULL);
if (m_last_value_format.get())
- m_last_value_format.reset((ValueFormat*)NULL);
- Debugger::Formatting::ValueFormats::Get(*this, m_last_value_format);
- // to find a summary we look for a direct summary, then if there is none
- // we look for a regex summary. if there is none we look for a system
- // summary (direct), and if also that fails, we look for a system
- // regex summary
+ m_last_value_format.reset(/*(ValueFormat*)NULL*/);
+ if (m_last_synthetic_filter.get())
+ m_last_synthetic_filter.reset(/*(SyntheticFilter*)NULL*/);
+ Debugger::Formatting::ValueFormats::Get(*this, m_last_value_format);
Debugger::Formatting::GetSummaryFormat(*this, m_last_summary_format);
+ Debugger::Formatting::GetSyntheticFilter(*this, m_last_synthetic_filter);
m_last_format_mgr_revision = Debugger::Formatting::ValueFormats::GetCurrentRevision();
@@ -1423,6 +1429,63 @@ ValueObject::GetSyntheticBitFieldChild (uint32_t from, uint32_t to, bool can_cre
return synthetic_child_sp;
}
+// your expression path needs to have a leading . or ->
+// (unless it somehow "looks like" an array, in which case it has
+// a leading [ symbol). while the [ is meaningful and should be shown
+// to the user, . and -> are just parser design, but by no means
+// added information for the user.. strip them off
+static const char*
+SkipLeadingExpressionPathSeparators(const char* expression)
+{
+ if (!expression || !expression[0])
+ return expression;
+ if (expression[0] == '.')
+ return expression+1;
+ if (expression[0] == '-' && expression[1] == '>')
+ return expression+2;
+ return expression;
+}
+
+lldb::ValueObjectSP
+ValueObject::GetSyntheticExpressionPathChild(const char* expression, bool can_create)
+{
+ ValueObjectSP synthetic_child_sp;
+ ConstString name_const_string(expression);
+ // Check if we have already created a synthetic array member in this
+ // valid object. If we have we will re-use it.
+ synthetic_child_sp = GetSyntheticChild (name_const_string);
+ if (!synthetic_child_sp)
+ {
+ // We haven't made a synthetic array member for expression yet, so
+ // lets make one and cache it for any future reference.
+ synthetic_child_sp = GetValueForExpressionPath(expression);
+
+ // Cache the value if we got one back...
+ if (synthetic_child_sp.get())
+ {
+ AddSyntheticChild(name_const_string, synthetic_child_sp.get());
+ synthetic_child_sp->SetName(SkipLeadingExpressionPathSeparators(expression));
+ synthetic_child_sp->m_is_expression_path_child = true;
+ }
+ }
+ return synthetic_child_sp;
+}
+
+void
+ValueObject::CalculateSyntheticValue (lldb::SyntheticValueType use_synthetic)
+{
+ if (use_synthetic == lldb::eNoSyntheticFilter)
+ return;
+
+ UpdateFormatsIfNeeded();
+
+ if (m_last_synthetic_filter.get() == NULL)
+ return;
+
+ m_synthetic_value = new ValueObjectSyntheticFilter(*this, m_last_synthetic_filter);
+
+}
+
void
ValueObject::CalculateDynamicValue (lldb::DynamicValueType use_dynamic)
{
@@ -1483,6 +1546,29 @@ ValueObject::GetDynamicValue (DynamicValueType use_dynamic)
return ValueObjectSP();
}
+// GetDynamicValue() returns a NULL SharedPointer if the object is not dynamic
+// or we do not really want a dynamic VO. this method instead returns this object
+// itself when making it synthetic has no meaning. this makes it much simpler
+// to replace the SyntheticValue for the ValueObject
+ValueObjectSP
+ValueObject::GetSyntheticValue (SyntheticValueType use_synthetic)
+{
+ if (use_synthetic == lldb::eNoSyntheticFilter)
+ return GetSP();
+
+ UpdateFormatsIfNeeded();
+
+ if (m_last_synthetic_filter.get() == NULL)
+ return GetSP();
+
+ CalculateSyntheticValue(use_synthetic);
+
+ if (m_synthetic_value)
+ return m_synthetic_value->GetSP();
+ else
+ return GetSP();
+}
+
bool
ValueObject::GetBaseClassPath (Stream &s)
{
@@ -2398,6 +2484,7 @@ ValueObject::DumpValueObject
bool show_location,
bool use_objc,
lldb::DynamicValueType use_dynamic,
+ bool use_synth,
bool scope_already_checked,
bool flat_output,
uint32_t omit_summary_depth
@@ -2545,7 +2632,10 @@ ValueObject::DumpValueObject
if (print_children && (!entry || entry->DoesPrintChildren() || !sum_cstr))
{
- const uint32_t num_children = valobj->GetNumChildren();
+ ValueObjectSP synth_vobj = valobj->GetSyntheticValue(use_synth ?
+ lldb::eUseSyntheticFilter :
+ lldb::eNoSyntheticFilter);
+ const uint32_t num_children = synth_vobj->GetNumChildren();
if (num_children)
{
if (flat_output)
@@ -2562,7 +2652,7 @@ ValueObject::DumpValueObject
for (uint32_t idx=0; idxGetChildAtIndex(idx, true));
+ ValueObjectSP child_sp(synth_vobj->GetChildAtIndex(idx, true));
if (child_sp.get())
{
DumpValueObject (s,
@@ -2575,6 +2665,7 @@ ValueObject::DumpValueObject
show_location,
false,
use_dynamic,
+ use_synth,
true,
flat_output,
omit_summary_depth > 1 ? omit_summary_depth - 1 : 0);
diff --git a/lldb/source/Core/ValueObjectSyntheticFilter.cpp b/lldb/source/Core/ValueObjectSyntheticFilter.cpp
new file mode 100644
index 000000000000..4756b1cea29f
--- /dev/null
+++ b/lldb/source/Core/ValueObjectSyntheticFilter.cpp
@@ -0,0 +1,170 @@
+//===-- ValueObjectSyntheticFilter.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "lldb/Core/ValueObjectSyntheticFilter.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/FormatClasses.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+
+using namespace lldb_private;
+
+ValueObjectSyntheticFilter::ValueObjectSyntheticFilter (ValueObject &parent, lldb::SyntheticFilterSP filter) :
+ ValueObject(parent),
+ m_address (),
+ m_type_sp(),
+m_use_synthetic (lldb::eUseSyntheticFilter),
+ m_synth_filter(filter)
+{
+ SetName (parent.GetName().AsCString());
+}
+
+ValueObjectSyntheticFilter::~ValueObjectSyntheticFilter()
+{
+ m_owning_valobj_sp.reset();
+}
+
+lldb::clang_type_t
+ValueObjectSyntheticFilter::GetClangType ()
+{
+ if (m_type_sp)
+ return m_value.GetClangType();
+ else
+ return m_parent->GetClangType();
+}
+
+ConstString
+ValueObjectSyntheticFilter::GetTypeName()
+{
+ const bool success = UpdateValueIfNeeded();
+ if (success && m_type_sp)
+ return ClangASTType::GetConstTypeName (GetClangType());
+ else
+ return m_parent->GetTypeName();
+}
+
+uint32_t
+ValueObjectSyntheticFilter::CalculateNumChildren()
+{
+ const bool success = UpdateValueIfNeeded();
+ if (!success)
+ return 0;
+ if (m_synth_filter.get())
+ return m_synth_filter->GetCount();
+ return 0;
+ if (success && m_type_sp)
+ return ClangASTContext::GetNumChildren (GetClangAST (), GetClangType(), true);
+ else
+ return m_parent->GetNumChildren();
+}
+
+clang::ASTContext *
+ValueObjectSyntheticFilter::GetClangAST ()
+{
+ const bool success = UpdateValueIfNeeded(false);
+ if (success && m_type_sp)
+ return m_type_sp->GetClangAST();
+ else
+ return m_parent->GetClangAST ();
+}
+
+size_t
+ValueObjectSyntheticFilter::GetByteSize()
+{
+ const bool success = UpdateValueIfNeeded();
+ if (success && m_type_sp)
+ return m_value.GetValueByteSize(GetClangAST(), NULL);
+ else
+ return m_parent->GetByteSize();
+}
+
+lldb::ValueType
+ValueObjectSyntheticFilter::GetValueType() const
+{
+ return m_parent->GetValueType();
+}
+
+bool
+ValueObjectSyntheticFilter::UpdateValue ()
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ if (!m_parent->UpdateValueIfNeeded())
+ {
+ // our parent could not update.. as we are meaningless without a parent, just stop
+ if (m_error.Success() && m_parent->GetError().Fail())
+ m_error = m_parent->GetError();
+ return false;
+ }
+
+ SetValueIsValid(true);
+ return true;
+}
+
+lldb::ValueObjectSP
+ValueObjectSyntheticFilter::GetChildAtIndex (uint32_t idx, bool can_create)
+{
+ if (!m_synth_filter.get())
+ return lldb::ValueObjectSP();
+ if (idx >= m_synth_filter->GetCount())
+ return lldb::ValueObjectSP();
+ return m_parent->GetSyntheticExpressionPathChild(m_synth_filter->GetExpressionPathAtIndex(idx).c_str(), can_create);
+}
+
+lldb::ValueObjectSP
+ValueObjectSyntheticFilter::GetChildMemberWithName (const ConstString &name, bool can_create)
+{
+ if (!m_synth_filter.get())
+ return lldb::ValueObjectSP();
+ uint32_t idx = GetIndexOfChildWithName(name);
+ if (idx >= m_synth_filter->GetCount())
+ return lldb::ValueObjectSP();
+ return m_parent->GetSyntheticExpressionPathChild(name.GetCString(), can_create);
+}
+
+uint32_t
+ValueObjectSyntheticFilter::GetIndexOfChildWithName (const ConstString &name)
+{
+ const char* name_cstr = name.GetCString();
+ for (int i = 0; i < m_synth_filter->GetCount(); i++)
+ {
+ const char* expr_cstr = m_synth_filter->GetExpressionPathAtIndex(i).c_str();
+ if (::strcmp(name_cstr, expr_cstr))
+ return i;
+ }
+ return UINT32_MAX;
+}
+
+bool
+ValueObjectSyntheticFilter::IsInScope ()
+{
+ return m_parent->IsInScope();
+}
+
diff --git a/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp
index b8a767c1780b..b2ca4ae7213c 100644
--- a/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp
+++ b/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp
@@ -31,7 +31,8 @@ static OptionDefinition
g_option_table[] =
{
{ LLDB_OPT_SET_1, false, "dynamic-type", 'd', required_argument, TargetInstanceSettings::g_dynamic_value_types,
- 0, eArgTypeNone, "Show the object as its full dynamic type, not its static type, if available."},
+ 0, eArgTypeNone, "Show the object as its full dynamic type, not its static type, if available."},
+ { LLDB_OPT_SET_1, false, "synthetic-type", 'S', required_argument, NULL, 0, eArgTypeBoolean, "Show the object obeying its synthetic provider, if available."},
{ LLDB_OPT_SET_1, false, "depth", 'D', required_argument, NULL, 0, eArgTypeCount, "Set the max recurse depth when dumping aggregate types (default is infinity)."},
{ LLDB_OPT_SET_1, false, "flat", 'F', no_argument, NULL, 0, eArgTypeNone, "Display results in a flat format that uses expression paths for each variable or member."},
{ LLDB_OPT_SET_1, false, "location", 'L', no_argument, NULL, 0, eArgTypeNone, "Show variable location information."},
@@ -105,7 +106,12 @@ OptionGroupValueObjectDisplay::SetOptionValue (CommandInterpreter &interpreter,
else
no_summary_depth = 1;
break;
-
+
+ case 'S':
+ use_synth = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("Invalid synthetic-type '%s'.\n", option_arg);
+ break;
default:
error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
break;
@@ -124,6 +130,7 @@ OptionGroupValueObjectDisplay::OptionParsingStarting (CommandInterpreter &interp
use_objc = false;
max_depth = UINT32_MAX;
ptr_depth = 0;
+ use_synth = true;
Target *target = interpreter.GetExecutionContext().target;
if (target != NULL)
diff --git a/lldb/test/functionalities/data-formatter/data-formatter-categories/TestDataFormatterCategories.py b/lldb/test/functionalities/data-formatter/data-formatter-categories/TestDataFormatterCategories.py
index b48462e69c50..ac370f70a184 100644
--- a/lldb/test/functionalities/data-formatter/data-formatter-categories/TestDataFormatterCategories.py
+++ b/lldb/test/functionalities/data-formatter/data-formatter-categories/TestDataFormatterCategories.py
@@ -319,8 +319,23 @@ class DataFormatterTestCase(TestBase):
'AShape',
'ARectangleStar'])
+ # check that synthetic children work into categories
+ self.runCmd("type synth add Rectangle --child w --category RectangleCategory")
+ self.runCmd("type category enable RectangleCategory")
+ self.runCmd("type summary add Rectangle -f \" \" -e --category RectangleCategory")
+ self.expect('frame variable r2',
+ substrs = ['w = 9'])
+ self.runCmd("type summary add Rectangle -f \" \" -e")
+ self.expect('frame variable r2', matching=False,
+ substrs = ['h = 16'])
+
# Now delete all categories
- self.runCmd("type category delete CircleCategory RectangleStarCategory BaseCategory")
+ self.runCmd("type category delete CircleCategory RectangleStarCategory BaseCategory RectangleCategory")
+
+ # last of all, check that a deleted category with synth does not blow us up
+ self.expect('frame variable r2',
+ substrs = ['w = 9',
+ 'h = 16'])
if __name__ == '__main__':
import atexit
diff --git a/lldb/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py b/lldb/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py
index f5a206b39f45..97aae5c8e1cb 100644
--- a/lldb/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py
+++ b/lldb/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py
@@ -182,7 +182,25 @@ class DataFormatterTestCase(TestBase):
self.expect("frame variable cool_pointer",
substrs = ['3,0,0'])
+ # test special symbols for formatting variables into summaries
+ self.runCmd("type summary add -f \"cool object @ ${var%L}\" i_am_cool")
+ self.runCmd("type summary delete \"i_am_cool [5]\"")
+ # this test might fail if the compiler tries to store
+ # these values into registers.. hopefully this is not
+ # going to be the case
+ self.expect("frame variable cool_array",
+ substrs = ['[0] = cool object @ 0x',
+ '[1] = cool object @ 0x',
+ '[2] = cool object @ 0x',
+ '[3] = cool object @ 0x',
+ '[4] = cool object @ 0x'])
+
+ self.runCmd("type summary add -f \"goofy\" i_am_cool")
+ self.runCmd("type summary add -f \"${var.second_cool%S}\" i_am_cooler")
+
+ self.expect("frame variable the_coolest_guy",
+ substrs = ['(i_am_cooler) the_coolest_guy = goofy'])
if __name__ == '__main__':
import atexit
diff --git a/lldb/test/functionalities/data-formatter/data-formatter-cpp/main.cpp b/lldb/test/functionalities/data-formatter/data-formatter-cpp/main.cpp
index 9224cb8a0a00..31f7c6bf9349 100644
--- a/lldb/test/functionalities/data-formatter/data-formatter-cpp/main.cpp
+++ b/lldb/test/functionalities/data-formatter/data-formatter-cpp/main.cpp
@@ -110,6 +110,8 @@ int main (int argc, const char * argv[])
char strarr[32] = "Hello world!";
char* strptr = "Hello world!";
+
+ i_am_cooler the_coolest_guy(1,2,3.14,6.28,'E','G');
return 0; // Set break point at this line.
}
diff --git a/lldb/test/functionalities/data-formatter/data-formatter-synth/Makefile b/lldb/test/functionalities/data-formatter/data-formatter-synth/Makefile
new file mode 100644
index 000000000000..314f1cb2f077
--- /dev/null
+++ b/lldb/test/functionalities/data-formatter/data-formatter-synth/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/test/functionalities/data-formatter/data-formatter-synth/TestDataFormatterSynth.py b/lldb/test/functionalities/data-formatter/data-formatter-synth/TestDataFormatterSynth.py
new file mode 100644
index 000000000000..c542e6a7735a
--- /dev/null
+++ b/lldb/test/functionalities/data-formatter/data-formatter-synth/TestDataFormatterSynth.py
@@ -0,0 +1,203 @@
+"""
+Test lldb data formatter subsystem.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+
+class DataFormatterTestCase(TestBase):
+
+ mydir = os.path.join("functionalities", "data-formatter", "data-formatter-synth")
+
+ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+ def test_with_dsym_and_run_command(self):
+ """Test data formatter commands."""
+ self.buildDsym()
+ self.data_formatter_commands()
+
+ def test_with_dwarf_and_run_command(self):
+ """Test data formatter commands."""
+ self.buildDwarf()
+ self.data_formatter_commands()
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ # Find the line number to break at.
+ self.line = line_number('main.cpp', '// Set break point at this line.')
+
+ def data_formatter_commands(self):
+ """Test that that file and class static variables display correctly."""
+ self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+ self.expect("breakpoint set -f main.cpp -l %d" % self.line,
+ BREAKPOINT_CREATED,
+ startstr = "Breakpoint created: 1: file ='main.cpp', line = %d, locations = 1" %
+ self.line)
+
+ self.runCmd("run", RUN_SUCCEEDED)
+
+ # The stop reason of the thread should be breakpoint.
+ self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+ substrs = ['stopped',
+ 'stop reason = breakpoint'])
+
+ # This is the function to remove the custom formats in order to have a
+ # clean slate for the next test case.
+ def cleanup():
+ self.runCmd('type format clear', check=False)
+ self.runCmd('type summary clear', check=False)
+ self.runCmd('type synth clear', check=False)
+
+ # Execute the cleanup function during test case tear down.
+ self.addTearDownHook(cleanup)
+
+ # Pick some values and check that the basics work
+ self.runCmd("type synth add BagOfInts --child x --child z")
+ self.expect("frame variable int_bag",
+ substrs = ['x = 6',
+ 'z = 8'])
+
+ # Check we can still access the missing child by summary
+ self.runCmd("type summary add BagOfInts -f \"y=${var.y}\"")
+ self.expect('frame variable int_bag',
+ substrs = ['y=7'])
+
+ # Even if we have synth children, the summary prevails
+ self.expect("frame variable int_bag", matching=False,
+ substrs = ['x = 6',
+ 'z = 8'])
+
+ # Summary+Synth must work together
+ self.runCmd("type summary add BagOfInts -f \"y=${var.y}\" -e")
+ self.expect('frame variable int_bag',
+ substrs = ['y=7',
+ 'x = 6',
+ 'z = 8'])
+
+ # Same output, but using Python
+ self.runCmd("type summary add BagOfInts -s \"return 'y='+valobj.GetChildMemberWithName('y').GetValue()\" -e")
+ self.expect('frame variable int_bag',
+ substrs = ['y=7',
+ 'x = 6',
+ 'z = 8'])
+
+ # If I skip summaries, still give me the artificial children
+ self.expect("frame variable int_bag -Y1",
+ substrs = ['x = 6',
+ 'z = 8'])
+
+ # Delete synth and check that the view reflects it immediately
+ self.runCmd("type synth delete BagOfInts")
+ self.expect("frame variable int_bag",
+ substrs = ['x = 6',
+ 'y = 7',
+ 'z = 8'])
+
+ # Add the synth again and check that it's honored deeper in the hierarchy
+ self.runCmd("type synth add BagOfInts --child x --child z")
+ self.expect('frame variable bag_bag',
+ substrs = ['x = y=70 {',
+ 'x = 69',
+ 'z = 71',
+ 'y = y=67 {',
+ 'x = 66',
+ 'z = 68'])
+ self.expect('frame variable bag_bag', matching=False,
+ substrs = ['y = 70',
+ 'y = 67'])
+
+ # Check that a synth can expand nested stuff
+ self.runCmd("type synth add BagOfBags --child x.y --child y.z")
+ self.expect('frame variable bag_bag',
+ substrs = ['x.y = 70',
+ 'y.z = 68'])
+
+ # ...even if we get -> and . wrong
+ self.runCmd("type synth add BagOfBags --child x.y --child \"y->z\"")
+ self.expect('frame variable bag_bag',
+ substrs = ['x.y = 70',
+ 'y->z = 68'])
+
+ # ...even bitfields
+ self.runCmd("type synth add BagOfBags --child x.y --child \"y->z[1-2]\"")
+ self.expect('frame variable bag_bag -T',
+ substrs = ['x.y = 70',
+ '(int:2) y->z[1-2] = 2'])
+
+ # ...even if we format the bitfields
+ self.runCmd("type synth add BagOfBags --child x.y --child \"y->y[0-0]\"")
+ self.runCmd("type format add \"int:1\" -f bool")
+ self.expect('frame variable bag_bag -T',
+ substrs = ['x.y = 70',
+ '(int:1) y->y[0-0] = true'])
+
+ # ...even if we use one-liner summaries
+ self.runCmd("type summary add -c BagOfBags")
+ self.expect('frame variable bag_bag',
+ substrs = ['(BagOfBags) bag_bag = (x.y=70, y->y[0-0]=true)'])
+
+ self.runCmd("type summary delete BagOfBags")
+
+ # now check we are dynamic (and arrays work)
+ self.runCmd("type synth add Plenty --child bitfield --child array[0] --child array[2]")
+ self.expect('frame variable plenty_of_stuff',
+ substrs = ['bitfield = 1',
+ 'array[0] = 5',
+ 'array[2] = 3'])
+
+ self.runCmd("n")
+ self.expect('frame variable plenty_of_stuff',
+ substrs = ['bitfield = 17',
+ 'array[0] = 5',
+ 'array[2] = 3'])
+
+ # skip synthetic children
+ self.expect('frame variable plenty_of_stuff -S no',
+ substrs = ['some_values = 0x0',
+ 'array = 0x',
+ 'array_size = 5'])
+
+
+ # check flat printing with synthetic children
+ self.expect('frame variable plenty_of_stuff --flat',
+ substrs = ['plenty_of_stuff.bitfield = 17',
+ '*(plenty_of_stuff.array) = 5',
+ '*(plenty_of_stuff.array) = 3'])
+
+ # check that we do not lose location information for our children
+ self.expect('frame variable plenty_of_stuff -L',
+ substrs = ['0x',
+ ': bitfield = 17'])
+
+ # check we work across pointer boundaries
+ self.expect('frame variable plenty_of_stuff.some_values -P1',
+ substrs = ['(BagOfInts *) plenty_of_stuff.some_values',
+ 'x = 5',
+ 'z = 7'])
+
+ # but not if we don't want to
+ self.runCmd("type synth add BagOfInts --child x --child z -p")
+ self.expect('frame variable plenty_of_stuff.some_values -P1',
+ substrs = ['(BagOfInts *) plenty_of_stuff.some_values',
+ 'x = 5',
+ 'y = 6',
+ 'z = 7'])
+
+ # check we're dynamic even if nested
+ self.runCmd("type synth add BagOfBags --child x.z")
+ self.expect('frame variable bag_bag',
+ substrs = ['x.z = 71'])
+
+ self.runCmd("n")
+ self.expect('frame variable bag_bag',
+ substrs = ['x.z = 12'])
+
+
+if __name__ == '__main__':
+ import atexit
+ lldb.SBDebugger.Initialize()
+ atexit.register(lambda: lldb.SBDebugger.Terminate())
+ unittest2.main()
diff --git a/lldb/test/functionalities/data-formatter/data-formatter-synth/main.cpp b/lldb/test/functionalities/data-formatter/data-formatter-synth/main.cpp
new file mode 100644
index 000000000000..11e279391380
--- /dev/null
+++ b/lldb/test/functionalities/data-formatter/data-formatter-synth/main.cpp
@@ -0,0 +1,83 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include
+#include
+#include
+
+struct BagOfInts
+{
+ int x;
+ int y;
+ int z;
+ BagOfInts(int X) :
+ x(X),
+ y(X+1),
+ z(X+2) {}
+};
+
+struct BagOfFloats
+{
+ float x;
+ float y;
+ float z;
+ BagOfFloats(float X) :
+ x(X+0.334),
+ y(X+0.500),
+ z(X+0.667) {}
+};
+
+struct BagOfBags
+{
+ BagOfInts x;
+ BagOfInts y;
+ BagOfFloats z;
+ BagOfFloats q;
+ BagOfBags() :
+ x('E'),
+ y('B'),
+ z(1.1),
+ q(20.11) {}
+};
+
+struct Plenty
+{
+ BagOfInts *some_values;
+ int* array;
+ int array_size;
+ int bitfield;
+
+ Plenty(int N, bool flagA, bool flagB) :
+ some_values(new BagOfInts(N)),
+ array(new int[N]),
+ array_size(N),
+ bitfield( (flagA ? 0x01 : 0x00) | (flagB ? 0x10 : 0x00) )
+ {
+ for (int j = 0; j < N; j++)
+ array[j] = N-j;
+ }
+};
+
+int main (int argc, const char * argv[])
+{
+ BagOfInts int_bag(6);
+ BagOfFloats float_bag(2.71);
+
+ BagOfBags bag_bag;
+
+ Plenty plenty_of_stuff(5,true,false);
+
+ plenty_of_stuff.bitfield = 0x11; // Set break point at this line.
+
+ bag_bag.x.z = 12;
+
+ return 0;
+
+}
+
diff --git a/lldb/www/varformats.html b/lldb/www/varformats.html
index 9260e0d65256..3b234c9c4a90 100755
--- a/lldb/www/varformats.html
+++ b/lldb/www/varformats.html
@@ -495,20 +495,38 @@
in fact it has a similar effect. If you add a % sign
followed by any one format name or abbreviation from the
above table after an expression path, the resulting
- object will be displyed using the chosen format (this is
- applicable to non-aggregate types only, with a few
- special exceptions discussed below).
- There are two more special format symbols that you can
- use only as part of a summary string: %V
- and %@
. The first one tells LLDB to ignore
- summary strings for the type of the object referred by
- the expression path and instead print the object's
- value. The second is only applicable to Objective-C
- classes, and tells LLDB to get the object's description
- from the Objective-C runtime. By default, if no format
- is provided, LLDB will try to get the object's summary,
- and if empty the object's value. If neither can be
- obtained, nothing will be displayed.
+ object will be displyed using the chosen format.
+
+ You can also use some other special format markers, not available
+ for type formatters, but which carry a special meaning when used in this
+ context:
+
+
+
+
+ Symbol |
+ Description |
+
+
+ %S |
+ Use this object's summary (the default for aggregate types) |
+
+
+ %V |
+ Use this object's value (the default for non-aggregate types) |
+
+
+ %@ |
+ Use a language-runtime specific description (for C++ this does nothing,
+ for Objective-C it calls the NSPrintForDebugger API) |
+
+
+ %L |
+ Use this object's location (memory address, register name, ...) |
+
+
+
+
As previously said, pointers and values are treated the
same way when getting to their members in an expression
path. However, if your expression path leads to a