Introduce a way for Languages to specify whether values of "reference types" are "nil" (not pointing to anything) or uninitialized (never made to point at anything)
This latter determination may or may not be possible on a per-language basis; and neither is mandatory to implement for any language
Use this knowledge in the ValueObjectPrinter to generalize the notion of IsObjCNil() and the respective printout
llvm-svn: 252663
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index 733207c..c066cc7 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -424,8 +424,11 @@
virtual bool
IsPossibleDynamicType ();
- virtual bool
- IsObjCNil ();
+ bool
+ IsNilReference ();
+
+ bool
+ IsUninitializedReference ();
virtual bool
IsBaseClass ()
diff --git a/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h b/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
index 54ef126..23d7ee2 100644
--- a/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
+++ b/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h
@@ -27,175 +27,179 @@
//#include <set>
namespace lldb_private {
+
+class ValueObjectPrinter
+{
+public:
+
+ ValueObjectPrinter (ValueObject* valobj,
+ Stream* s);
- class ValueObjectPrinter
- {
- public:
-
- ValueObjectPrinter (ValueObject* valobj,
- Stream* s);
-
- ValueObjectPrinter (ValueObject* valobj,
- Stream* s,
- const DumpValueObjectOptions& options);
-
- ~ValueObjectPrinter () {}
-
- bool
- PrintValueObject ();
-
- protected:
- typedef std::set<uint64_t> InstancePointersSet;
- typedef std::shared_ptr<InstancePointersSet> InstancePointersSetSP;
-
- InstancePointersSetSP m_printed_instance_pointers;
-
- // only this class (and subclasses, if any) should ever be concerned with
- // the depth mechanism
- ValueObjectPrinter (ValueObject* valobj,
- Stream* s,
- const DumpValueObjectOptions& options,
- const DumpValueObjectOptions::PointerDepth& ptr_depth,
- uint32_t curr_depth,
- InstancePointersSetSP printed_instance_pointers);
-
- // we should actually be using delegating constructors here
- // but some versions of GCC still have trouble with those
- void
- Init (ValueObject* valobj,
- Stream* s,
- const DumpValueObjectOptions& options,
- const DumpValueObjectOptions::PointerDepth& ptr_depth,
- uint32_t curr_depth,
- InstancePointersSetSP printed_instance_pointers);
-
- bool
- GetMostSpecializedValue ();
-
- const char*
- GetDescriptionForDisplay ();
-
- const char*
- GetRootNameForDisplay (const char* if_fail = nullptr);
-
- bool
- ShouldPrintValueObject ();
-
- bool
- ShouldPrintValidation ();
-
- bool
- IsNil ();
-
- bool
- IsPtr ();
-
- bool
- IsRef ();
-
- bool
- IsInstancePointer ();
-
- bool
- IsAggregate ();
-
- bool
- PrintValidationMarkerIfNeeded ();
-
- bool
- PrintValidationErrorIfNeeded ();
-
- bool
- PrintLocationIfNeeded ();
-
- void
- PrintDecl ();
-
- bool
- CheckScopeIfNeeded ();
-
- bool
- ShouldPrintEmptyBrackets (bool value_printed,
- bool summary_printed);
-
- TypeSummaryImpl*
- GetSummaryFormatter (bool null_if_omitted = true);
-
- void
- GetValueSummaryError (std::string& value,
- std::string& summary,
- std::string& error);
-
- bool
- PrintValueAndSummaryIfNeeded (bool& value_printed,
- bool& summary_printed);
-
- bool
- PrintObjectDescriptionIfNeeded (bool value_printed,
- bool summary_printed);
-
- bool
- ShouldPrintChildren (bool is_failed_description,
- DumpValueObjectOptions::PointerDepth& curr_ptr_depth);
-
- bool
- ShouldExpandEmptyAggregates ();
-
- ValueObject*
- GetValueObjectForChildrenGeneration ();
-
- void
- PrintChildrenPreamble ();
-
- void
- PrintChildrenPostamble (bool print_dotdotdot);
-
- void
- PrintChild (lldb::ValueObjectSP child_sp,
- const DumpValueObjectOptions::PointerDepth& curr_ptr_depth);
-
- uint32_t
- GetMaxNumChildrenToPrint (bool& print_dotdotdot);
-
- void
- PrintChildren (bool value_printed,
- bool summary_printed,
- const DumpValueObjectOptions::PointerDepth& curr_ptr_depth);
-
- void
- PrintChildrenIfNeeded (bool value_printed,
- bool summary_printed);
-
- bool
- PrintChildrenOneLiner (bool hide_names);
-
- private:
-
- ValueObject *m_orig_valobj;
- ValueObject *m_valobj;
- Stream *m_stream;
- DumpValueObjectOptions m_options;
- Flags m_type_flags;
- CompilerType m_compiler_type;
- DumpValueObjectOptions::PointerDepth m_ptr_depth;
- uint32_t m_curr_depth;
- LazyBool m_should_print;
- LazyBool m_is_nil;
- LazyBool m_is_ptr;
- LazyBool m_is_ref;
- LazyBool m_is_aggregate;
- LazyBool m_is_instance_ptr;
- std::pair<TypeSummaryImpl*,bool> m_summary_formatter;
- std::string m_value;
- std::string m_summary;
- std::string m_error;
- bool m_val_summary_ok;
- std::pair<TypeValidatorResult,std::string> m_validation;
-
- friend struct StringSummaryFormat;
-
- DISALLOW_COPY_AND_ASSIGN(ValueObjectPrinter);
- };
+ ValueObjectPrinter (ValueObject* valobj,
+ Stream* s,
+ const DumpValueObjectOptions& options);
+
+ ~ValueObjectPrinter () {}
+
+ bool
+ PrintValueObject ();
+
+protected:
+ typedef std::set<uint64_t> InstancePointersSet;
+ typedef std::shared_ptr<InstancePointersSet> InstancePointersSetSP;
+
+ InstancePointersSetSP m_printed_instance_pointers;
+
+ // only this class (and subclasses, if any) should ever be concerned with
+ // the depth mechanism
+ ValueObjectPrinter (ValueObject* valobj,
+ Stream* s,
+ const DumpValueObjectOptions& options,
+ const DumpValueObjectOptions::PointerDepth& ptr_depth,
+ uint32_t curr_depth,
+ InstancePointersSetSP printed_instance_pointers);
+
+ // we should actually be using delegating constructors here
+ // but some versions of GCC still have trouble with those
+ void
+ Init (ValueObject* valobj,
+ Stream* s,
+ const DumpValueObjectOptions& options,
+ const DumpValueObjectOptions::PointerDepth& ptr_depth,
+ uint32_t curr_depth,
+ InstancePointersSetSP printed_instance_pointers);
+
+ bool
+ GetMostSpecializedValue ();
+
+ const char*
+ GetDescriptionForDisplay ();
+
+ const char*
+ GetRootNameForDisplay (const char* if_fail = nullptr);
+
+ bool
+ ShouldPrintValueObject ();
+
+ bool
+ ShouldPrintValidation ();
+
+ bool
+ IsNil ();
+
+ bool
+ IsUninitialized ();
+
+ bool
+ IsPtr ();
+
+ bool
+ IsRef ();
+
+ bool
+ IsInstancePointer ();
+
+ bool
+ IsAggregate ();
+
+ bool
+ PrintValidationMarkerIfNeeded ();
+
+ bool
+ PrintValidationErrorIfNeeded ();
+
+ bool
+ PrintLocationIfNeeded ();
+
+ void
+ PrintDecl ();
+
+ bool
+ CheckScopeIfNeeded ();
+
+ bool
+ ShouldPrintEmptyBrackets (bool value_printed,
+ bool summary_printed);
+
+ TypeSummaryImpl*
+ GetSummaryFormatter (bool null_if_omitted = true);
+
+ void
+ GetValueSummaryError (std::string& value,
+ std::string& summary,
+ std::string& error);
+
+ bool
+ PrintValueAndSummaryIfNeeded (bool& value_printed,
+ bool& summary_printed);
+
+ bool
+ PrintObjectDescriptionIfNeeded (bool value_printed,
+ bool summary_printed);
+
+ bool
+ ShouldPrintChildren (bool is_failed_description,
+ DumpValueObjectOptions::PointerDepth& curr_ptr_depth);
+
+ bool
+ ShouldExpandEmptyAggregates ();
+
+ ValueObject*
+ GetValueObjectForChildrenGeneration ();
+
+ void
+ PrintChildrenPreamble ();
+
+ void
+ PrintChildrenPostamble (bool print_dotdotdot);
+
+ void
+ PrintChild (lldb::ValueObjectSP child_sp,
+ const DumpValueObjectOptions::PointerDepth& curr_ptr_depth);
+
+ uint32_t
+ GetMaxNumChildrenToPrint (bool& print_dotdotdot);
+
+ void
+ PrintChildren (bool value_printed,
+ bool summary_printed,
+ const DumpValueObjectOptions::PointerDepth& curr_ptr_depth);
+
+ void
+ PrintChildrenIfNeeded (bool value_printed,
+ bool summary_printed);
+
+ bool
+ PrintChildrenOneLiner (bool hide_names);
+
+private:
+
+ ValueObject *m_orig_valobj;
+ ValueObject *m_valobj;
+ Stream *m_stream;
+ DumpValueObjectOptions m_options;
+ Flags m_type_flags;
+ CompilerType m_compiler_type;
+ DumpValueObjectOptions::PointerDepth m_ptr_depth;
+ uint32_t m_curr_depth;
+ LazyBool m_should_print;
+ LazyBool m_is_nil;
+ LazyBool m_is_uninit;
+ LazyBool m_is_ptr;
+ LazyBool m_is_ref;
+ LazyBool m_is_aggregate;
+ LazyBool m_is_instance_ptr;
+ std::pair<TypeSummaryImpl*,bool> m_summary_formatter;
+ std::string m_value;
+ std::string m_summary;
+ std::string m_error;
+ bool m_val_summary_ok;
+ std::pair<TypeValidatorResult,std::string> m_validation;
+
+ friend struct StringSummaryFormat;
+
+ DISALLOW_COPY_AND_ASSIGN(ValueObjectPrinter);
+};
} // namespace lldb_private
diff --git a/lldb/include/lldb/Target/Language.h b/lldb/include/lldb/Target/Language.h
index 8eb5ed2..28c6d48 100644
--- a/lldb/include/lldb/Target/Language.h
+++ b/lldb/include/lldb/Target/Language.h
@@ -123,6 +123,17 @@
IsLogicalTrue (ValueObject& valobj,
Error& error);
+ // for a ValueObject of some "reference type", if the value points to the
+ // nil/null object, this method returns true
+ virtual bool
+ IsNilReference (ValueObject& valobj);
+
+ // for a ValueObject of some "reference type", if the language provides a technique
+ // to decide whether the reference has ever been assigned to some object, this method
+ // will return true if such detection is possible, and if the reference has never been assigned
+ virtual bool
+ IsUninitializedReference (ValueObject& valobj);
+
// These are accessors for general information about the Languages lldb knows about:
static lldb::LanguageType
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index 7513555..fa3f1ff 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -2145,15 +2145,23 @@
}
bool
-ValueObject::IsObjCNil ()
+ValueObject::IsNilReference ()
{
- const uint32_t mask = eTypeIsObjC | eTypeIsPointer;
- bool isObjCpointer = (((GetCompilerType().GetTypeInfo(NULL)) & mask) == mask);
- if (!isObjCpointer)
- return false;
- bool canReadValue = true;
- bool isZero = GetValueAsUnsigned(0,&canReadValue) == 0;
- return canReadValue && isZero;
+ if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage()))
+ {
+ return language->IsNilReference(*this);
+ }
+ return false;
+}
+
+bool
+ValueObject::IsUninitializedReference ()
+{
+ if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage()))
+ {
+ return language->IsUninitializedReference(*this);
+ }
+ return false;
}
// This allows you to create an array member using and index
diff --git a/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/lldb/source/DataFormatters/ValueObjectPrinter.cpp
index 4bc33fd..4289496 100644
--- a/lldb/source/DataFormatters/ValueObjectPrinter.cpp
+++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp
@@ -73,6 +73,7 @@
assert (m_stream && "cannot print to a NULL Stream");
m_should_print = eLazyBoolCalculate;
m_is_nil = eLazyBoolCalculate;
+ m_is_uninit = eLazyBoolCalculate;
m_is_ptr = eLazyBoolCalculate;
m_is_ref = eLazyBoolCalculate;
m_is_aggregate = eLazyBoolCalculate;
@@ -100,12 +101,12 @@
PrintDecl();
}
-
+
bool value_printed = false;
bool summary_printed = false;
m_val_summary_ok = PrintValueAndSummaryIfNeeded (value_printed,summary_printed);
-
+
if (m_val_summary_ok)
PrintChildrenIfNeeded (value_printed, summary_printed);
else
@@ -194,8 +195,8 @@
ValueObjectPrinter::GetRootNameForDisplay (const char* if_fail)
{
const char *root_valobj_name = m_options.m_root_valobj_name.empty() ?
- m_valobj->GetName().AsCString() :
- m_options.m_root_valobj_name.c_str();
+ m_valobj->GetName().AsCString() :
+ m_options.m_root_valobj_name.c_str();
return root_valobj_name ? root_valobj_name : if_fail;
}
@@ -211,11 +212,19 @@
ValueObjectPrinter::IsNil ()
{
if (m_is_nil == eLazyBoolCalculate)
- m_is_nil = m_valobj->IsObjCNil() ? eLazyBoolYes : eLazyBoolNo;
+ m_is_nil = m_valobj->IsNilReference() ? eLazyBoolYes : eLazyBoolNo;
return m_is_nil == eLazyBoolYes;
}
bool
+ValueObjectPrinter::IsUninitialized ()
+{
+ if (m_is_uninit == eLazyBoolCalculate)
+ m_is_uninit = m_valobj->IsUninitializedReference() ? eLazyBoolYes : eLazyBoolNo;
+ return m_is_uninit == eLazyBoolYes;
+}
+
+bool
ValueObjectPrinter::IsPtr ()
{
if (m_is_ptr == eLazyBoolCalculate)
@@ -426,6 +435,8 @@
{
if (IsNil())
summary.assign("nil");
+ else if (IsUninitialized())
+ summary.assign("<uninitialized>");
else if (m_options.m_omit_summary_depth == 0)
{
TypeSummaryImpl* entry = GetSummaryFormatter();
@@ -476,7 +487,7 @@
// the value if this thing is nil
// (but show the value if the user passes a format explicitly)
TypeSummaryImpl* entry = GetSummaryFormatter();
- if (!IsNil() && !m_value.empty() && (entry == NULL || (entry->DoesPrintValue(m_valobj) || m_options.m_format != eFormatDefault) || m_summary.empty()) && !m_options.m_hide_value)
+ if (!IsNil() && !IsUninitialized() && !m_value.empty() && (entry == NULL || (entry->DoesPrintValue(m_valobj) || m_options.m_format != eFormatDefault) || m_summary.empty()) && !m_options.m_hide_value)
{
if (m_options.m_hide_pointer_value && IsPointerValue(m_valobj->GetCompilerType())) {}
else
@@ -503,7 +514,7 @@
if (ShouldPrintValueObject())
{
// let's avoid the overly verbose no description error for a nil thing
- if (m_options.m_use_objc && !IsNil())
+ if (m_options.m_use_objc && !IsNil() && !IsUninitialized())
{
if (!m_options.m_hide_value || !m_options.m_hide_name)
m_stream->Printf(" ");
@@ -571,6 +582,10 @@
{
const bool is_ref = IsRef ();
const bool is_ptr = IsPtr ();
+ const bool is_uninit = IsUninitialized();
+
+ if (is_uninit)
+ return false;
TypeSummaryImpl* entry = GetSummaryFormatter();
diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
index e8d008c..1cec626 100644
--- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
+++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
@@ -863,3 +863,15 @@
return false;
}
+
+bool
+ObjCLanguage::IsNilReference (ValueObject& valobj)
+{
+ const uint32_t mask = eTypeIsObjC | eTypeIsPointer;
+ bool isObjCpointer = (((valobj.GetCompilerType().GetTypeInfo(nullptr)) & mask) == mask);
+ if (!isObjCpointer)
+ return false;
+ bool canReadValue = true;
+ bool isZero = valobj.GetValueAsUnsigned(0,&canReadValue) == 0;
+ return canReadValue && isZero;
+}
diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
index 0f96ff8..e30aa18 100644
--- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
+++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
@@ -153,6 +153,9 @@
GetFormatterPrefixSuffix (ValueObject& valobj, ConstString type_hint,
std::string& prefix, std::string& suffix) override;
+ bool
+ IsNilReference (ValueObject& valobj) override;
+
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp
index 3a53a6b..2d75bde 100644
--- a/lldb/source/Target/Language.cpp
+++ b/lldb/source/Target/Language.cpp
@@ -358,6 +358,18 @@
return eLazyBoolCalculate;
}
+bool
+Language::IsNilReference (ValueObject& valobj)
+{
+ return false;
+}
+
+bool
+Language::IsUninitializedReference (ValueObject& valobj)
+{
+ return false;
+}
+
//----------------------------------------------------------------------
// Constructor
//----------------------------------------------------------------------