This is the work I was building up to with my patches yesterday

Introduce the notion of Language-based formatter prefix/suffix
This is meant for languages that share certain data types but present them in syntatically different ways, such that LLDB can now have language-based awareness of which of the syntax variations it has to present to the user when formatting those values

This is goodness for new languages and interoperability, but is NFC for existing languages. As such, existing tests cover this

llvm-svn: 249587
This commit is contained in:
Enrico Granata 2015-10-07 18:36:53 +00:00
parent 75230398c2
commit 675f49bbd5
18 changed files with 480 additions and 132 deletions

View File

@ -79,7 +79,7 @@ public:
virtual lldb::LanguageType
GetLanguageType () const = 0;
bool
virtual bool
IsTopLevelFunction (Function& function);
virtual lldb::TypeCategoryImplSP
@ -106,6 +106,13 @@ public:
virtual std::unique_ptr<TypeScavenger>
GetTypeScavenger ();
// if an individual data formatter can apply to several types and cross a language boundary
// it makes sense for individual languages to want to customize the printing of values of that
// type by appending proper prefix/suffix information in language-specific ways
virtual bool
GetFormatterPrefixSuffix (ValueObject& valobj, ConstString type_hint,
std::string& prefix, std::string& suffix);
// These are accessors for general information about the Languages lldb knows about:
static lldb::LanguageType

View File

@ -17,6 +17,7 @@
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
@ -42,6 +43,8 @@ lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, St
bool
lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
static ConstString g_TypeHint("CFBag");
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
return false;
@ -84,7 +87,9 @@ lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& str
ValueObjectSP count_sp;
StreamString expr;
expr.Printf("(int)CFBagGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExpressionCompleted)
EvaluateExpressionOptions options;
options.SetResultIsInternal(true);
if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp, options) != eExpressionCompleted)
return false;
if (!count_sp)
return false;
@ -98,8 +103,21 @@ lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& str
if (error.Fail())
return false;
}
stream.Printf("@\"%u value%s\"",
count,(count == 1 ? "" : "s"));
std::string prefix,suffix;
if (Language* language = Language::FindPlugin(options.GetLanguage()))
{
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
{
prefix.clear();
suffix.clear();
}
}
stream.Printf("%s\"%u value%s\"%s",
prefix.c_str(),
count,(count == 1 ? "" : "s"),
suffix.c_str());
return true;
}
@ -236,6 +254,8 @@ lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Strea
bool
lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
static ConstString g_TypeHint("CFBinaryHeap");
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
return false;
@ -278,7 +298,9 @@ lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stre
ValueObjectSP count_sp;
StreamString expr;
expr.Printf("(int)CFBinaryHeapGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExpressionCompleted)
EvaluateExpressionOptions options;
options.SetResultIsInternal(true);
if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp, options) != eExpressionCompleted)
return false;
if (!count_sp)
return false;
@ -292,7 +314,20 @@ lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stre
if (error.Fail())
return false;
}
stream.Printf("@\"%u item%s\"",
count,(count == 1 ? "" : "s"));
std::string prefix,suffix;
if (Language* language = Language::FindPlugin(options.GetLanguage()))
{
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
{
prefix.clear();
suffix.clear();
}
}
stream.Printf("%s\"%u item%s\"%s",
prefix.c_str(),
count,(count == 1 ? "" : "s"),
suffix.c_str());
return true;
}

View File

@ -20,6 +20,7 @@
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Process.h"
@ -64,7 +65,7 @@ lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream&
{
uint64_t offset = 5 * ptr_size;
ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true));
StreamString summary_stream;
bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
if (was_nsstring_ok && summary_stream.GetSize() > 0)
@ -295,6 +296,145 @@ lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream
return true;
}
static void
NSNumber_FormatChar (ValueObject& valobj,
Stream& stream,
char value,
lldb::LanguageType lang)
{
static ConstString g_TypeHint("NSNumber:char");
std::string prefix,suffix;
if (Language* language = Language::FindPlugin(lang))
{
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
{
prefix.clear();
suffix.clear();
}
}
stream.Printf("%s%hhd%s",
prefix.c_str(),
value,
suffix.c_str());
}
static void
NSNumber_FormatShort (ValueObject& valobj,
Stream& stream,
short value,
lldb::LanguageType lang)
{
static ConstString g_TypeHint("NSNumber:short");
std::string prefix,suffix;
if (Language* language = Language::FindPlugin(lang))
{
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
{
prefix.clear();
suffix.clear();
}
}
stream.Printf("%s%hd%s",
prefix.c_str(),
value,
suffix.c_str());
}
static void
NSNumber_FormatInt (ValueObject& valobj,
Stream& stream,
int value,
lldb::LanguageType lang)
{
static ConstString g_TypeHint("NSNumber:int");
std::string prefix,suffix;
if (Language* language = Language::FindPlugin(lang))
{
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
{
prefix.clear();
suffix.clear();
}
}
stream.Printf("%s%d%s",
prefix.c_str(),
value,
suffix.c_str());
}
static void
NSNumber_FormatLong (ValueObject& valobj,
Stream& stream,
uint64_t value,
lldb::LanguageType lang)
{
static ConstString g_TypeHint("NSNumber:long");
std::string prefix,suffix;
if (Language* language = Language::FindPlugin(lang))
{
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
{
prefix.clear();
suffix.clear();
}
}
stream.Printf("%s%" PRId64 "%s",
prefix.c_str(),
value,
suffix.c_str());
}
static void
NSNumber_FormatFloat (ValueObject& valobj,
Stream& stream,
float value,
lldb::LanguageType lang)
{
static ConstString g_TypeHint("NSNumber:float");
std::string prefix,suffix;
if (Language* language = Language::FindPlugin(lang))
{
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
{
prefix.clear();
suffix.clear();
}
}
stream.Printf("%s%f%s",
prefix.c_str(),
value,
suffix.c_str());
}
static void
NSNumber_FormatDouble (ValueObject& valobj,
Stream& stream,
double value,
lldb::LanguageType lang)
{
static ConstString g_TypeHint("NSNumber:double");
std::string prefix,suffix;
if (Language* language = Language::FindPlugin(lang))
{
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
{
prefix.clear();
suffix.clear();
}
}
stream.Printf("%s%g%s",
prefix.c_str(),
value,
suffix.c_str());
}
bool
lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
@ -333,19 +473,19 @@ lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream&
switch (i_bits)
{
case 0:
stream.Printf("(char)%hhd",(char)value);
NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
break;
case 1:
case 4:
stream.Printf("(short)%hd",(short)value);
NSNumber_FormatShort(valobj, stream, (short)value, options.GetLanguage());
break;
case 2:
case 8:
stream.Printf("(int)%d",(int)value);
NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
break;
case 3:
case 12:
stream.Printf("(long)%" PRId64,value);
NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
break;
default:
return false;
@ -366,19 +506,19 @@ lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream&
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error);
if (error.Fail())
return false;
stream.Printf("(char)%hhd",(char)value);
NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
break;
case 2: // 0B0010
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error);
if (error.Fail())
return false;
stream.Printf("(short)%hd",(short)value);
NSNumber_FormatShort(valobj, stream, (short)value, options.GetLanguage());
break;
case 3: // 0B0011
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
if (error.Fail())
return false;
stream.Printf("(int)%d",(int)value);
NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
break;
case 17: // 0B10001
data_location += 8;
@ -386,7 +526,7 @@ lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream&
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
if (error.Fail())
return false;
stream.Printf("(long)%" PRId64,value);
NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
break;
case 5: // 0B0101
{
@ -394,7 +534,7 @@ lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream&
if (error.Fail())
return false;
float flt_value = *((float*)&flt_as_int);
stream.Printf("(float)%f",flt_value);
NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage());
break;
}
case 6: // 0B0110
@ -403,7 +543,7 @@ lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream&
if (error.Fail())
return false;
double dbl_value = *((double*)&dbl_as_lng);
stream.Printf("(double)%g",dbl_value);
NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage());
break;
}
default:

View File

@ -18,6 +18,7 @@
#include "lldb/Expression/FunctionCaller.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
#include "lldb/Target/Target.h"
@ -230,6 +231,8 @@ namespace lldb_private {
bool
lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
static ConstString g_TypeHint("NSArray");
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
return false;
@ -285,16 +288,29 @@ lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& s
return false;
}
stream.Printf("@\"%" PRIu64 " object%s\"",
std::string prefix,suffix;
if (Language* language = Language::FindPlugin(options.GetLanguage()))
{
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
{
prefix.clear();
suffix.clear();
}
}
stream.Printf("%s%" PRIu64 " %s%s%s",
prefix.c_str(),
value,
value == 1 ? "" : "s");
"element",
value == 1 ? "" : "s",
suffix.c_str());
return true;
}
lldb_private::formatters::NSArrayMSyntheticFrontEnd::NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
SyntheticChildrenFrontEnd(*valobj_sp),
m_exe_ctx_ref(),
m_ptr_size(8),
m_exe_ctx_ref(),
m_ptr_size(8),
m_id_type(),
m_children()
{
@ -524,11 +540,11 @@ lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::~NSArrayMSyntheticFron
}
lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
SyntheticChildrenFrontEnd (*valobj_sp.get()),
m_exe_ctx_ref (),
m_ptr_size (8),
m_items (0),
m_data_ptr (0)
SyntheticChildrenFrontEnd (*valobj_sp.get()),
m_exe_ctx_ref (),
m_ptr_size (8),
m_items (0),
m_data_ptr (0)
{
if (valobj_sp)
{
@ -686,7 +702,10 @@ lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetChildAtIndex (
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
lldb::ValueObjectSP valobj_sp = CallSelectorOnObject(m_backend,"id","objectAtIndex:",idx);
if (valobj_sp)
{
valobj_sp->SetPreferredDisplayLanguage(m_backend.GetPreferredDisplayLanguage());
valobj_sp->SetName(ConstString(idx_name.GetData()));
}
return valobj_sp;
}

View File

@ -17,6 +17,7 @@
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
@ -46,13 +47,13 @@ static CompilerType
GetLLDBNSPairType (TargetSP target_sp)
{
CompilerType compiler_type;
ClangASTContext *target_ast_context = target_sp->GetScratchClangASTContext();
if (target_ast_context)
{
ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair");
compiler_type = target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>(g___lldb_autogen_nspair);
if (!compiler_type)
@ -213,6 +214,7 @@ template<bool name_entries>
bool
lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
static ConstString g_TypeHint("NSDictionary");
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
return false;
@ -260,14 +262,14 @@ lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stre
value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
}
/*else if (!strcmp(class_name,"__NSCFDictionary"))
{
Error error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error);
if (error.Fail())
return false;
if (is_64bit)
value &= ~0x0f1f000000000000UL;
}*/
{
Error error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error);
if (error.Fail())
return false;
if (is_64bit)
value &= ~0x0f1f000000000000UL;
}*/
else
{
auto& map(NSDictionary_Additionals::GetAdditionalSummaries());
@ -278,11 +280,22 @@ lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stre
return false;
}
stream.Printf("%s%" PRIu64 " %s%s",
(name_entries ? "@\"" : ""),
std::string prefix,suffix;
if (Language* language = Language::FindPlugin(options.GetLanguage()))
{
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
{
prefix.clear();
suffix.clear();
}
}
stream.Printf("%s%" PRIu64 " %s%s%s",
prefix.c_str(),
value,
(name_entries ? (value == 1 ? "entry" : "entries") : (value == 1 ? "key/value pair" : "key/value pairs")),
(name_entries ? "\"" : ""));
"key/value pair",
value == 1 ? "" : "s",
suffix.c_str());
return true;
}
@ -295,7 +308,10 @@ SyntheticChildrenFrontEnd* lldb_private::formatters::NSDictionarySyntheticFrontE
if (!runtime)
return NULL;
if (!valobj_sp->IsPointerType())
CompilerType valobj_type(valobj_sp->GetCompilerType());
Flags flags(valobj_type.GetTypeInfo());
if (flags.IsClear(eTypeIsPointer))
{
Error error;
valobj_sp = valobj_sp->AddressOf(error);
@ -359,6 +375,8 @@ lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIn
lldb::ValueObjectSP child_sp;
EvaluateExpressionOptions options;
options.SetKeepInMemory(true);
options.SetLanguage(lldb::eLanguageTypeObjC_plus_plus);
options.SetResultIsInternal(true);
m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(),
GetViableFrame(m_backend.GetTargetSP().get()),
child_sp,

View File

@ -17,6 +17,7 @@
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
@ -198,6 +199,8 @@ template<bool cf_style>
bool
lldb_private::formatters::NSSetSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
static ConstString g_TypeHint("NSSet");
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
return false;
@ -245,26 +248,26 @@ lldb_private::formatters::NSSetSummaryProvider (ValueObject& valobj, Stream& str
value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
}
/*else if (!strcmp(class_name,"__NSCFSet"))
{
Error error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error);
if (error.Fail())
return false;
if (is_64bit)
value &= ~0x1fff000000000000UL;
}
else if (!strcmp(class_name,"NSCountedSet"))
{
Error error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
if (error.Fail())
return false;
value = process_sp->ReadUnsignedIntegerFromMemory(value + (is_64bit ? 20 : 12), 4, 0, error);
if (error.Fail())
return false;
if (is_64bit)
value &= ~0x1fff000000000000UL;
}*/
{
Error error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error);
if (error.Fail())
return false;
if (is_64bit)
value &= ~0x1fff000000000000UL;
}
else if (!strcmp(class_name,"NSCountedSet"))
{
Error error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
if (error.Fail())
return false;
value = process_sp->ReadUnsignedIntegerFromMemory(value + (is_64bit ? 20 : 12), 4, 0, error);
if (error.Fail())
return false;
if (is_64bit)
value &= ~0x1fff000000000000UL;
}*/
else
{
auto& map(NSSet_Additionals::GetAdditionalSummaries());
@ -275,11 +278,22 @@ lldb_private::formatters::NSSetSummaryProvider (ValueObject& valobj, Stream& str
return false;
}
stream.Printf("%s%" PRIu64 " %s%s",
(cf_style ? "@\"" : ""),
std::string prefix,suffix;
if (Language* language = Language::FindPlugin(options.GetLanguage()))
{
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
{
prefix.clear();
suffix.clear();
}
}
stream.Printf("%s%" PRIu64 " %s%s%s",
prefix.c_str(),
value,
(cf_style ? (value == 1 ? "value" : "values") : (value == 1 ? "object" : "objects")),
(cf_style ? "\"" : ""));
"element",
value == 1 ? "" : "s",
suffix.c_str());
return true;
}
@ -292,7 +306,10 @@ SyntheticChildrenFrontEnd* lldb_private::formatters::NSSetSyntheticFrontEndCreat
if (!runtime)
return NULL;
if (!valobj_sp->IsPointerType())
CompilerType valobj_type(valobj_sp->GetCompilerType());
Flags flags(valobj_type.GetTypeInfo());
if (flags.IsClear(eTypeIsPointer))
{
Error error;
valobj_sp = valobj_sp->AddressOf(error);
@ -492,10 +509,10 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex (size_t idx)
process_sp->GetAddressByteSize());
set_item.valobj_sp =
CreateValueObjectFromData(idx_name.GetData(),
data,
m_exe_ctx_ref,
m_backend.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID));
CreateValueObjectFromData(idx_name.GetData(),
data,
m_exe_ctx_ref,
m_backend.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID));
}
return set_item.valobj_sp;
}
@ -590,7 +607,7 @@ lldb::ValueObjectSP
lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
lldb::addr_t m_objs_addr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
uint32_t num_children = CalculateNumChildren();
if (idx >= num_children)
@ -660,10 +677,10 @@ lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
process_sp->GetAddressByteSize());
set_item.valobj_sp =
CreateValueObjectFromData(idx_name.GetData(),
data,
m_exe_ctx_ref,
m_backend.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID));
CreateValueObjectFromData(idx_name.GetData(),
data,
m_exe_ctx_ref,
m_backend.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID));
}
return set_item.valobj_sp;
}
@ -740,3 +757,4 @@ lldb_private::formatters::NSSetSummaryProvider<true> (ValueObject& valobj, Strea
template bool
lldb_private::formatters::NSSetSummaryProvider<false> (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options);

View File

@ -18,6 +18,7 @@
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/ProcessStructReader.h"
@ -55,6 +56,8 @@ GetNSPathStore2Type (Target &target)
bool
lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& summary_options)
{
static ConstString g_TypeHint("NSString");
ProcessSP process_sp = valobj.GetProcessSP();
if (!process_sp)
return false;
@ -85,7 +88,7 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
bool is_tagged_ptr = (0 == strcmp(class_name,"NSTaggedPointerString")) && descriptor->GetTaggedPointerInfo();
// for a tagged pointer, the descriptor has everything we need
if (is_tagged_ptr)
return NSTaggedString_SummaryProvider(descriptor, stream);
return NSTaggedString_SummaryProvider(valobj, descriptor, stream, summary_options);
auto& additionals_map(NSString_Additionals::GetAdditionalSummaries());
auto iter = additionals_map.find(class_name_cs), end = additionals_map.end();
@ -144,6 +147,20 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
return true;
}
std::string prefix,suffix;
if (Language* language = Language::FindPlugin(summary_options.GetLanguage()))
{
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
{
prefix.clear();
suffix.clear();
}
}
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetPrefixToken(prefix);
options.SetSuffixToken(suffix);
if (is_mutable)
{
uint64_t location = 2 * ptr_size + valobj_addr;
@ -152,11 +169,9 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
return false;
if (has_explicit_length && is_unicode)
{
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetPrefixToken("@");
options.SetQuote('"');
options.SetSourceSize(explicit_length);
options.SetNeedsZeroTermination(false);
@ -167,11 +182,9 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
}
else
{
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location+1);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetPrefixToken("@");
options.SetSourceSize(explicit_length);
options.SetNeedsZeroTermination(false);
options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
@ -184,11 +197,9 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
{
uint64_t location = 3 * ptr_size + valobj_addr;
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetPrefixToken("@");
options.SetQuote('"');
options.SetSourceSize(explicit_length);
options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
@ -214,11 +225,9 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
if (error.Fail())
return false;
}
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetPrefixToken("@");
options.SetQuote('"');
options.SetSourceSize(explicit_length);
options.SetNeedsZeroTermination(has_explicit_length == false);
@ -233,11 +242,9 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
explicit_length = reader.GetField<uint32_t>(ConstString("lengthAndRef")) >> 20;
lldb::addr_t location = valobj.GetValueAsUnsigned(0) + ptr_size + 4;
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetPrefixToken("@");
options.SetQuote('"');
options.SetSourceSize(explicit_length);
options.SetNeedsZeroTermination(has_explicit_length == false);
@ -261,11 +268,9 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
has_explicit_length = true;
location++;
}
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetPrefixToken("@");
options.SetSourceSize(explicit_length);
options.SetNeedsZeroTermination(!has_explicit_length);
options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
@ -284,10 +289,8 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
return false;
if (has_explicit_length && !has_null)
explicit_length++; // account for the fact that there is no NULL and we need to have one added
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetPrefixToken("@");
options.SetStream(&stream);
options.SetSourceSize(explicit_length);
options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
@ -331,8 +334,10 @@ lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject&
}
bool
lldb_private::formatters::NSTaggedString_SummaryProvider (ObjCLanguageRuntime::ClassDescriptorSP descriptor, Stream& stream)
lldb_private::formatters::NSTaggedString_SummaryProvider (ValueObject& valobj, ObjCLanguageRuntime::ClassDescriptorSP descriptor, Stream& stream, const TypeSummaryOptions& summary_options)
{
static ConstString g_TypeHint("NSString");
if (!descriptor)
return false;
uint64_t len_bits = 0, data_bits = 0;
@ -348,13 +353,25 @@ lldb_private::formatters::NSTaggedString_SummaryProvider (ObjCLanguageRuntime::C
if (len_bits > g_fiveBitMaxLen)
return false;
std::string prefix,suffix;
if (Language* language = Language::FindPlugin(summary_options.GetLanguage()))
{
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
{
prefix.clear();
suffix.clear();
}
}
// this is a fairly ugly trick - pretend that the numeric value is actually a char*
// this works under a few assumptions:
// little endian architecture
// sizeof(uint64_t) > g_MaxNonBitmaskedLen
if (len_bits <= g_MaxNonBitmaskedLen)
{
stream.Printf("@\"%s\"",(const char*)&data_bits);
stream.Printf("%s",prefix.c_str());
stream.Printf("\"%s\"",(const char*)&data_bits);
stream.Printf("%s",suffix.c_str());
return true;
}
@ -381,6 +398,8 @@ lldb_private::formatters::NSTaggedString_SummaryProvider (ObjCLanguageRuntime::C
bytes.insert(bytes.begin(), sixBitToCharLookup[packed]);
}
stream.Printf("@\"%s\"",&bytes[0]);
stream.Printf("%s",prefix.c_str());
stream.Printf("\"%s\"",&bytes[0]);
stream.Printf("%s",suffix.c_str());
return true;
}

View File

@ -22,7 +22,7 @@ namespace lldb_private {
NSStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options);
bool
NSTaggedString_SummaryProvider (ObjCLanguageRuntime::ClassDescriptorSP descriptor, Stream& stream);
NSTaggedString_SummaryProvider (ValueObject& valobj, ObjCLanguageRuntime::ClassDescriptorSP descriptor, Stream& stream, const TypeSummaryOptions& summary_options);
bool
NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options);

View File

@ -770,3 +770,84 @@ ObjCLanguage::GetTypeScavenger ()
return std::unique_ptr<TypeScavenger>(new ObjCTypeScavenger());
}
bool
ObjCLanguage::GetFormatterPrefixSuffix (ValueObject& valobj, ConstString type_hint,
std::string& prefix, std::string& suffix)
{
static ConstString g_CFBag("CFBag");
static ConstString g_CFBinaryHeap("CFBinaryHeap");
static ConstString g_NSNumberChar("NSNumber:char");
static ConstString g_NSNumberShort("NSNumber:short");
static ConstString g_NSNumberInt("NSNumber:int");
static ConstString g_NSNumberLong("NSNumber:long");
static ConstString g_NSNumberFloat("NSNumber:float");
static ConstString g_NSNumberDouble("NSNumber:double");
static ConstString g_NSData("NSData");
static ConstString g_NSArray("NSArray");
static ConstString g_NSString("NSString");
static ConstString g_NSStringStar("NSString*");
if (type_hint.IsEmpty())
return false;
prefix.clear();
suffix.clear();
if (type_hint == g_CFBag ||
type_hint == g_CFBinaryHeap)
{
prefix = "@";
return true;
}
if (type_hint == g_NSNumberChar)
{
prefix = "(char)";
return true;
}
if (type_hint == g_NSNumberShort)
{
prefix = "(short)";
return true;
}
if (type_hint == g_NSNumberInt)
{
prefix = "(int)";
return true;
}
if (type_hint == g_NSNumberLong)
{
prefix = "(long)";
return true;
}
if (type_hint == g_NSNumberFloat)
{
prefix = "(float)";
return true;
}
if (type_hint == g_NSNumberDouble)
{
prefix = "(double)";
return true;
}
if (type_hint == g_NSData ||
type_hint == g_NSArray)
{
prefix = "@\"";
suffix = "\"";
return true;
}
if (type_hint == g_NSString ||
type_hint == g_NSStringStar)
{
prefix = "@";
return true;
}
return false;
}

View File

@ -149,6 +149,10 @@ public:
std::unique_ptr<TypeScavenger>
GetTypeScavenger () override;
bool
GetFormatterPrefixSuffix (ValueObject& valobj, ConstString type_hint,
std::string& prefix, std::string& suffix) override;
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------

View File

@ -315,6 +315,13 @@ Language::TypeScavenger::Find (ExecutionContextScope *exe_scope,
return 0;
}
bool
Language::GetFormatterPrefixSuffix (ValueObject& valobj, ConstString type_hint,
std::string& prefix, std::string& suffix)
{
return false;
}
//----------------------------------------------------------------------
// Constructor
//----------------------------------------------------------------------

View File

@ -211,16 +211,16 @@ class ObjCDataFormatterTestCase(TestBase):
def nscontainers_data_formatter_commands(self):
self.expect('frame variable newArray newDictionary newMutableDictionary cfdict_ref mutable_dict_ref cfarray_ref mutable_array_ref',
substrs = ['(NSArray *) newArray = ','@"50 objects"',
substrs = ['(NSArray *) newArray = ','@"50 elements"',
'(NSDictionary *) newDictionary = ',' 12 key/value pairs',
'(NSDictionary *) newMutableDictionary = ',' 21 key/value pairs',
'(CFDictionaryRef) cfdict_ref = ','@"3 entries"',
'(CFMutableDictionaryRef) mutable_dict_ref = ','@"12 entries"',
'(CFArrayRef) cfarray_ref = ','@"3 objects"',
'(CFMutableArrayRef) mutable_array_ref = ','@"11 objects"'])
'(CFDictionaryRef) cfdict_ref = ','3 key/value pairs',
'(CFMutableDictionaryRef) mutable_dict_ref = ','12 key/value pairs',
'(CFArrayRef) cfarray_ref = ','@"3 elements"',
'(CFMutableArrayRef) mutable_array_ref = ','@"11 elements"'])
self.expect('frame variable nscounted_set',
substrs = ['(NSCountedSet *) nscounted_set = ','5 objects'])
substrs = ['(NSCountedSet *) nscounted_set = ','5 elements'])
self.expect('frame variable iset1 iset2 imset',
substrs = ['4 indexes','512 indexes','10 indexes'])

View File

@ -50,13 +50,13 @@ class DataFormatterOneIsSingularTestCase(TestBase):
# Now check that we are displaying Cocoa classes correctly
self.expect('frame variable key',
substrs = ['@"1 object"'])
substrs = ['@"1 element"'])
self.expect('frame variable key', matching=False,
substrs = ['1 objects'])
substrs = ['1 elements'])
self.expect('frame variable value',
substrs = ['@"1 object"'])
substrs = ['@"1 element"'])
self.expect('frame variable value', matching=False,
substrs = ['1 objects'])
substrs = ['1 elements'])
self.expect('frame variable dict',
substrs = ['1 key/value pair'])
self.expect('frame variable dict', matching=False,
@ -66,9 +66,9 @@ class DataFormatterOneIsSingularTestCase(TestBase):
self.expect('frame variable mutable_bag_ref', matching=False,
substrs = ['1 values'])
self.expect('frame variable nscounted_set',
substrs = ['1 object'])
substrs = ['1 element'])
self.expect('frame variable nscounted_set', matching=False,
substrs = ['1 objects'])
substrs = ['1 elements'])
self.expect('frame variable imset',
substrs = ['1 index'])
self.expect('frame variable imset', matching=False,
@ -78,9 +78,9 @@ class DataFormatterOneIsSingularTestCase(TestBase):
self.expect('frame variable binheap_ref', matching=False,
substrs = ['1 items'])
self.expect('frame variable nsset',
substrs = ['1 object'])
substrs = ['1 element'])
self.expect('frame variable nsset', matching=False,
substrs = ['1 objects'])
substrs = ['1 elements'])
self.expect('frame variable immutableData',
substrs = ['1 byte'])
self.expect('frame variable immutableData', matching=False,

View File

@ -46,19 +46,19 @@ class NSArraySyntheticTestCase(TestBase):
# Now check that we are displaying Cocoa classes correctly
self.expect('frame variable arr',
substrs = ['@"6 objects"'])
substrs = ['@"6 elements"'])
self.expect('frame variable other_arr',
substrs = ['@"4 objects"'])
substrs = ['@"4 elements"'])
self.expect('frame variable arr --ptr-depth 1',
substrs = ['@"6 objects"','[0] = 0x','[1] = 0x','[2] = 0x','[3] = 0x','[4] = 0x','[5] = 0x'])
substrs = ['@"6 elements"','[0] = 0x','[1] = 0x','[2] = 0x','[3] = 0x','[4] = 0x','[5] = 0x'])
self.expect('frame variable other_arr --ptr-depth 1',
substrs = ['@"4 objects"','[0] = 0x','[1] = 0x','[2] = 0x','[3] = 0x'])
substrs = ['@"4 elements"','[0] = 0x','[1] = 0x','[2] = 0x','[3] = 0x'])
self.expect('frame variable arr --ptr-depth 1 -d no-run-target',
substrs = ['@"6 objects"','@"hello"','@"world"','@"this"','@"is"','@"me"','@"http://www.apple.com'])
substrs = ['@"6 elements"','@"hello"','@"world"','@"this"','@"is"','@"me"','@"http://www.apple.com'])
self.expect('frame variable other_arr --ptr-depth 1 -d no-run-target',
substrs = ['@"4 objects"','(int)5','@"a string"','@"6 objects"'])
substrs = ['@"4 elements"','(int)5','@"a string"','@"6 elements"'])
self.expect('frame variable other_arr --ptr-depth 2 -d no-run-target',
substrs = ['@"4 objects"','@"6 objects" {','@"hello"','@"world"','@"this"','@"is"','@"me"','@"http://www.apple.com'])
substrs = ['@"4 elements"','@"6 elements" {','@"hello"','@"world"','@"this"','@"is"','@"me"','@"http://www.apple.com'])
self.assertTrue(self.frame().FindVariable("arr").MightHaveChildren(), "arr says it does not have children!")
self.assertTrue(self.frame().FindVariable("other_arr").MightHaveChildren(), "arr says it does not have children!")

View File

@ -54,13 +54,13 @@ class NSDictionarySyntheticTestCase(TestBase):
self.expect('frame variable mutabledict --ptr-depth 1',
substrs = ['4 key/value pairs','[0] = ','key = 0x','value = 0x','[1] = ','[2] = ','[3] = '])
self.expect('frame variable dictionary --ptr-depth 1 --dynamic-type no-run-target',
substrs = ['3 key/value pairs','@"bar"','@"2 objects"','@"baz"','2 key/value pairs'])
substrs = ['3 key/value pairs','@"bar"','@"2 elements"','@"baz"','2 key/value pairs'])
self.expect('frame variable mutabledict --ptr-depth 1 --dynamic-type no-run-target',
substrs = ['4 key/value pairs','(int)23','@"123"','@"http://www.apple.com"','@"puartist"','3 key/value pairs'])
substrs = ['4 key/value pairs','(int)23','@"123"','@"http://www.apple.com"','@"sourceofstuff"','3 key/value pairs'])
self.expect('frame variable mutabledict --ptr-depth 2 --dynamic-type no-run-target',
substrs = ['4 key/value pairs','(int)23','@"123"','@"http://www.apple.com"','@"puartist"','3 key/value pairs','@"bar"','@"2 objects"'])
substrs = ['4 key/value pairs','(int)23','@"123"','@"http://www.apple.com"','@"sourceofstuff"','3 key/value pairs','@"bar"','@"2 elements"'])
self.expect('frame variable mutabledict --ptr-depth 3 --dynamic-type no-run-target',
substrs = ['4 key/value pairs','(int)23','@"123"','@"http://www.apple.com"','@"puartist"','3 key/value pairs','@"bar"','@"2 objects"','(int)1','@"two"'])
substrs = ['4 key/value pairs','(int)23','@"123"','@"http://www.apple.com"','@"sourceofstuff"','3 key/value pairs','@"bar"','@"2 elements"','(int)1','@"two"'])
self.assertTrue(self.frame().FindVariable("dictionary").MightHaveChildren(), "dictionary says it does not have children!")
self.assertTrue(self.frame().FindVariable("mutabledict").MightHaveChildren(), "mutable says it does not have children!")

View File

@ -22,7 +22,7 @@ int main (int argc, const char * argv[])
[mutabledict setObject:@"123" forKey:@23];
[mutabledict setObject:[NSURL URLWithString:@"http://www.apple.com"] forKey:@"foobar"];
[mutabledict setObject:@[@"a",@12] forKey:@57];
[mutabledict setObject:dictionary forKey:@"puartist"];
[mutabledict setObject:dictionary forKey:@"sourceofstuff"];
[pool drain];// Set break point at this line.
return 0;

View File

@ -46,29 +46,29 @@ class NSSetSyntheticTestCase(TestBase):
# Now check that we are displaying Cocoa classes correctly
self.expect('frame variable set',
substrs = ['4 objects'])
substrs = ['4 elements'])
self.expect('frame variable mutable',
substrs = ['9 objects'])
substrs = ['9 elements'])
self.expect('frame variable set --ptr-depth 1 -d run -T',
substrs = ['4 objects','[0]','[1]','[2]','[3]','hello','world','(int)1','(int)2'])
substrs = ['4 elements','[0]','[1]','[2]','[3]','hello','world','(int)1','(int)2'])
self.expect('frame variable mutable --ptr-depth 1 -d run -T',
substrs = ['9 objects','(int)5','@"3 objects"','@"www.apple.com"','(int)3','@"world"','(int)4'])
substrs = ['9 elements','(int)5','@"3 elements"','@"www.apple.com"','(int)3','@"world"','(int)4'])
self.runCmd("next")
self.expect('frame variable mutable',
substrs = ['0 objects'])
substrs = ['0 elements'])
self.runCmd("next")
self.expect('frame variable mutable',
substrs = ['4 objects'])
substrs = ['4 elements'])
self.expect('frame variable mutable --ptr-depth 1 -d run -T',
substrs = ['4 objects','[0]','[1]','[2]','[3]','hello','world','(int)1','(int)2'])
substrs = ['4 elements','[0]','[1]','[2]','[3]','hello','world','(int)1','(int)2'])
self.runCmd("next")
self.expect('frame variable mutable',
substrs = ['4 objects'])
substrs = ['4 elements'])
self.expect('frame variable mutable --ptr-depth 1 -d run -T',
substrs = ['4 objects','[0]','[1]','[2]','[3]','hello','world','(int)1','(int)2'])
substrs = ['4 elements','[0]','[1]','[2]','[3]','hello','world','(int)1','(int)2'])
if __name__ == '__main__':
import atexit

View File

@ -52,7 +52,7 @@ class SyntheticFilterRecomputingTestCase(TestBase):
if self.TraceOn():
self.runCmd("expr --dynamic-type run-target --ptr-depth 1 -- x")
self.assertTrue(id_x.GetSummary() == '@"5 objects"', "array does not get correct summary")
self.assertTrue(id_x.GetSummary() == '@"5 elements"', "array does not get correct summary")
self.runCmd("next")
self.runCmd("frame select 0")