Added support for looking up the complete type for
Objective-C classes.  This allows LLDB to find
ivars declared in class extensions in modules other
than where the debugger is currently stopped (we
already supported this when the debugger was
stopped in the same module as the definition).

This involved the following main changes:

- The ObjCLanguageRuntime now knows how to hunt
  for the authoritative version of an Objective-C
  type.  It looks for the symbol indicating a
  definition, and then gets the type from the
  module containing that symbol.

- ValueObjects now report their type with a
  potential override, and the override is set if
  the type of the ValueObject is an Objective-C
  class or pointer type that is defined somewhere
  other than the original reported type.  This
  means that "frame variable" will always use the
  complete type if one is available.

- The ClangASTSource now looks for the complete
  type when looking for ivars.  This means that
  "expr" will always use the complete type if one
  is available.

- I added a testcase that verifies that both
  "frame variable" and "expr" work.


git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@151214 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/lldb/Core/ValueObject.h b/include/lldb/Core/ValueObject.h
index 566d9e5..c64e7b8 100644
--- a/include/lldb/Core/ValueObject.h
+++ b/include/lldb/Core/ValueObject.h
@@ -492,6 +492,12 @@
     SetNeedsUpdate ();
     
     virtual ~ValueObject();
+    
+    clang::ASTContext *
+    GetClangAST ();
+    
+    lldb::clang_type_t
+    GetClangType ();
 
     //------------------------------------------------------------------
     // Sublasses must implement the functions below.
@@ -499,12 +505,6 @@
     virtual size_t
     GetByteSize() = 0;
 
-    virtual clang::ASTContext *
-    GetClangAST () = 0;
-
-    virtual lldb::clang_type_t
-    GetClangType () = 0;
-
     virtual lldb::ValueType
     GetValueType() const = 0;
 
@@ -1084,6 +1084,8 @@
     std::string         m_object_desc_str; // Cached result of the "object printer".  This differs from the summary
                                               // in that the summary is consed up by us, the object_desc_string is builtin.
 
+    ClangASTType        m_override_type;// If the type of the value object should be overridden, the type to impose.
+    
     ValueObjectManager *m_manager;      // This object is managed by the root object (any ValueObject that gets created
                                         // without a parent.)  The manager gets passed through all the generations of
                                         // dependent objects, and will keep the whole cluster of objects alive as long
@@ -1119,7 +1121,8 @@
                         m_is_bitfield_for_scalar:1,
                         m_is_expression_path_child:1,
                         m_is_child_at_offset:1,
-                        m_is_getting_summary:1;
+                        m_is_getting_summary:1,
+                        m_did_calculate_complete_objc_class_type:1;
     
     friend class ClangExpressionDeclMap;  // For GetValue
     friend class ClangExpressionVariable; // For SetName
@@ -1188,11 +1191,24 @@
     DataExtractor &
     GetDataExtractor ();
     
+    //------------------------------------------------------------------
+    // Sublasses must implement the functions below.
+    //------------------------------------------------------------------
+    
+    virtual clang::ASTContext *
+    GetClangASTImpl () = 0;
+    
+    virtual lldb::clang_type_t
+    GetClangTypeImpl () = 0;
+    
 private:
     //------------------------------------------------------------------
     // For ValueObject only
     //------------------------------------------------------------------
     
+    virtual ClangASTType
+    MaybeCalculateCompleteType ();
+    
     lldb::ValueObjectSP
     GetValueForExpressionPath_Impl(const char* expression_cstr,
                                    const char** first_unparsed,
diff --git a/include/lldb/Core/ValueObjectChild.h b/include/lldb/Core/ValueObjectChild.h
index df80122..2e0384e 100644
--- a/include/lldb/Core/ValueObjectChild.h
+++ b/include/lldb/Core/ValueObjectChild.h
@@ -50,18 +50,6 @@
         return m_bitfield_bit_offset;
     }
 
-    virtual clang::ASTContext *
-    GetClangAST ()
-    {
-        return m_clang_ast;
-    }
-
-    virtual lldb::clang_type_t
-    GetClangType ()
-    {
-        return m_clang_type;
-    }
-
     virtual lldb::ValueType
     GetValueType() const;
 
@@ -90,6 +78,18 @@
     virtual bool
     UpdateValue ();
 
+    virtual clang::ASTContext *
+    GetClangASTImpl ()
+    {
+        return m_clang_ast;
+    }
+    
+    virtual lldb::clang_type_t
+    GetClangTypeImpl ()
+    {
+        return m_clang_type;
+    }
+    
     clang::ASTContext *m_clang_ast; // The clang AST that the clang type comes from
     void *m_clang_type; // The type of the child in question within the parent (m_parent_sp)
     ConstString m_type_name;
diff --git a/include/lldb/Core/ValueObjectConstResult.h b/include/lldb/Core/ValueObjectConstResult.h
index 54c017c..d665efb 100644
--- a/include/lldb/Core/ValueObjectConstResult.h
+++ b/include/lldb/Core/ValueObjectConstResult.h
@@ -75,12 +75,6 @@
     virtual size_t
     GetByteSize();
 
-    virtual clang::ASTContext *
-    GetClangAST ();
-
-    virtual lldb::clang_type_t
-    GetClangType ();
-
     virtual lldb::ValueType
     GetValueType() const;
 
@@ -141,6 +135,12 @@
 protected:
     virtual bool
     UpdateValue ();
+    
+    virtual clang::ASTContext *
+    GetClangASTImpl ();
+    
+    virtual lldb::clang_type_t
+    GetClangTypeImpl ();
 
     // CalculateDynamicValue doesn't change the dynamic value, since this can get
     // called at any time and you can't reliably fetch the dynamic value at any time.
diff --git a/include/lldb/Core/ValueObjectDynamicValue.h b/include/lldb/Core/ValueObjectDynamicValue.h
index 361599a..a6fdab4 100644
--- a/include/lldb/Core/ValueObjectDynamicValue.h
+++ b/include/lldb/Core/ValueObjectDynamicValue.h
@@ -33,12 +33,6 @@
         virtual size_t
         GetByteSize();
         
-        virtual clang::ASTContext *
-        GetClangAST ();
-        
-        virtual lldb::clang_type_t
-        GetClangType ();
-        
         virtual ConstString
         GetTypeName();
         
@@ -85,6 +79,12 @@
         virtual bool
         UpdateValue ();
         
+        virtual clang::ASTContext *
+        GetClangASTImpl ();
+        
+        virtual lldb::clang_type_t
+        GetClangTypeImpl ();
+        
         ClangASTType m_cast_type;
         
     private:
@@ -111,12 +111,6 @@
     virtual size_t
     GetByteSize();
 
-    virtual clang::ASTContext *
-    GetClangAST ();
-
-    virtual lldb::clang_type_t
-    GetClangType ();
-
     virtual ConstString
     GetTypeName();
 
@@ -172,6 +166,12 @@
 protected:
     virtual bool
     UpdateValue ();
+    
+    virtual clang::ASTContext *
+    GetClangASTImpl ();
+    
+    virtual lldb::clang_type_t
+    GetClangTypeImpl ();
 
     Address  m_address;  ///< The variable that this value object is based upon
     lldb::TypeSP m_type_sp;
diff --git a/include/lldb/Core/ValueObjectMemory.h b/include/lldb/Core/ValueObjectMemory.h
index 83a5eb9..6cc337b 100644
--- a/include/lldb/Core/ValueObjectMemory.h
+++ b/include/lldb/Core/ValueObjectMemory.h
@@ -44,12 +44,6 @@
     virtual size_t
     GetByteSize();
 
-    virtual clang::ASTContext *
-    GetClangAST ();
-
-    virtual lldb::clang_type_t
-    GetClangType ();
-
     virtual ConstString
     GetTypeName();
 
@@ -68,6 +62,12 @@
 protected:
     virtual bool
     UpdateValue ();
+    
+    virtual clang::ASTContext *
+    GetClangASTImpl ();
+    
+    virtual lldb::clang_type_t
+    GetClangTypeImpl ();
 
     Address  m_address;  ///< The variable that this value object is based upon
     lldb::TypeSP m_type_sp;
diff --git a/include/lldb/Core/ValueObjectRegister.h b/include/lldb/Core/ValueObjectRegister.h
index dda1556..dab3784 100644
--- a/include/lldb/Core/ValueObjectRegister.h
+++ b/include/lldb/Core/ValueObjectRegister.h
@@ -34,12 +34,6 @@
     virtual size_t
     GetByteSize();
 
-    virtual clang::ASTContext *
-    GetClangAST ();
-
-    virtual lldb::clang_type_t
-    GetClangType ();
-
     virtual lldb::ValueType
     GetValueType () const
     {
@@ -58,6 +52,12 @@
 protected:
     virtual bool
     UpdateValue ();
+    
+    virtual clang::ASTContext *
+    GetClangASTImpl ();
+    
+    virtual lldb::clang_type_t
+    GetClangTypeImpl ();
 
     lldb::RegisterContextSP m_reg_ctx_sp;
 
@@ -81,12 +81,6 @@
     virtual size_t
     GetByteSize();
 
-    virtual clang::ASTContext *
-    GetClangAST ();
-
-    virtual lldb::clang_type_t
-    GetClangType ();
-
     virtual lldb::ValueType
     GetValueType () const
     {
@@ -112,6 +106,12 @@
 protected:
     virtual bool
     UpdateValue ();
+    
+    virtual clang::ASTContext *
+    GetClangASTImpl ();
+    
+    virtual lldb::clang_type_t
+    GetClangTypeImpl ();
 
     lldb::RegisterContextSP m_reg_ctx_sp;
     const RegisterSet *m_reg_set;
@@ -139,12 +139,6 @@
     virtual size_t
     GetByteSize();
 
-    virtual clang::ASTContext *
-    GetClangAST ();
-
-    virtual lldb::clang_type_t
-    GetClangType ();
-
     virtual lldb::ValueType
     GetValueType () const
     {
@@ -166,6 +160,12 @@
 protected:
     virtual bool
     UpdateValue ();
+    
+    virtual clang::ASTContext *
+    GetClangASTImpl ();
+    
+    virtual lldb::clang_type_t
+    GetClangTypeImpl ();
 
     lldb::RegisterContextSP m_reg_ctx_sp;
     RegisterInfo m_reg_info;
diff --git a/include/lldb/Core/ValueObjectSyntheticFilter.h b/include/lldb/Core/ValueObjectSyntheticFilter.h
index 01eafe6..1ef6e4d 100644
--- a/include/lldb/Core/ValueObjectSyntheticFilter.h
+++ b/include/lldb/Core/ValueObjectSyntheticFilter.h
@@ -36,13 +36,7 @@
 
     virtual size_t
     GetByteSize();
-
-    virtual clang::ASTContext *
-    GetClangAST ();
-
-    virtual lldb::clang_type_t
-    GetClangType ();
-
+    
     virtual ConstString
     GetTypeName();
 
@@ -116,6 +110,12 @@
 protected:
     virtual bool
     UpdateValue ();
+    
+    virtual clang::ASTContext *
+    GetClangASTImpl ();
+    
+    virtual lldb::clang_type_t
+    GetClangTypeImpl ();
 
     Address  m_address;  ///< The variable that this value object is based upon
     lldb::TypeSP m_type_sp;
diff --git a/include/lldb/Core/ValueObjectVariable.h b/include/lldb/Core/ValueObjectVariable.h
index 20c9589..eec952c 100644
--- a/include/lldb/Core/ValueObjectVariable.h
+++ b/include/lldb/Core/ValueObjectVariable.h
@@ -34,12 +34,6 @@
     virtual size_t
     GetByteSize();
 
-    virtual clang::ASTContext *
-    GetClangAST ();
-
-    virtual lldb::clang_type_t
-    GetClangType ();
-
     virtual ConstString
     GetTypeName();
 
@@ -64,6 +58,12 @@
 protected:
     virtual bool
     UpdateValue ();
+    
+    virtual clang::ASTContext *
+    GetClangASTImpl ();
+    
+    virtual lldb::clang_type_t
+    GetClangTypeImpl ();
 
     lldb::VariableSP  m_variable_sp;  ///< The variable that this value object is based upon
 
diff --git a/include/lldb/Symbol/ClangASTContext.h b/include/lldb/Symbol/ClangASTContext.h
index 02d53e4..105ec3f 100644
--- a/include/lldb/Symbol/ClangASTContext.h
+++ b/include/lldb/Symbol/ClangASTContext.h
@@ -869,6 +869,13 @@
     
     static bool
     IsObjCClassType (lldb::clang_type_t clang_type);
+    
+    static bool
+    IsObjCObjectPointerType (lldb::clang_type_t clang_type, lldb::clang_type_t *target_type);
+    
+    static bool
+    GetObjCClassName (lldb::clang_type_t clang_type,
+                      std::string &class_name);
 
     static bool
     IsCharType (lldb::clang_type_t clang_type);
diff --git a/include/lldb/Symbol/Type.h b/include/lldb/Symbol/Type.h
index 92a847f..18fea12 100644
--- a/include/lldb/Symbol/Type.h
+++ b/include/lldb/Symbol/Type.h
@@ -265,6 +265,18 @@
     
     bool
     IsRealObjCClass();
+    
+    bool
+    IsCompleteObjCClass()
+    {
+        return m_flags.is_complete_objc_class;
+    }
+    
+    void
+    SetIsCompleteObjCClass(bool is_complete_objc_class)
+    {
+        m_flags.is_complete_objc_class = is_complete_objc_class;
+    }
 
 protected:
     ConstString m_name;
@@ -276,7 +288,11 @@
     uint32_t m_byte_size;
     Declaration m_decl;
     lldb::clang_type_t m_clang_type;
-    ResolveState m_clang_type_resolve_state;
+    
+    struct Flags {
+        ResolveState    clang_type_resolve_state : 2;
+        bool            is_complete_objc_class   : 1;
+    } m_flags;
 
     Type *
     GetEncodingType ();
diff --git a/include/lldb/Target/ObjCLanguageRuntime.h b/include/lldb/Target/ObjCLanguageRuntime.h
index 05cdce6..fe12047 100644
--- a/include/lldb/Target/ObjCLanguageRuntime.h
+++ b/include/lldb/Target/ObjCLanguageRuntime.h
@@ -18,6 +18,7 @@
 // Project includes
 #include "lldb/lldb-private.h"
 #include "lldb/Core/PluginInterface.h"
+#include "lldb/Symbol/Type.h"
 #include "lldb/Target/LanguageRuntime.h"
 
 namespace lldb_private {
@@ -64,6 +65,9 @@
     void
     AddToClassNameCache (lldb::addr_t class_addr, const TypeAndOrName &class_or_type_name);
     
+    lldb::TypeSP
+    LookupInCompleteClassCache (ConstString &name);
+    
     virtual ClangUtilityFunction *
     CreateObjectChecker (const char *) = 0;
     
@@ -246,6 +250,9 @@
     typedef std::map<lldb::addr_t,TypeAndOrName> ClassNameMap;
     typedef ClassNameMap::iterator ClassNameIterator;
     ClassNameMap m_class_name_cache;
+    
+    typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap;
+    CompleteClassMap m_complete_class_cache;
 
     DISALLOW_COPY_AND_ASSIGN (ObjCLanguageRuntime);
 };
diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp
index 0c75aff..15885eb 100644
--- a/source/Core/ValueObject.cpp
+++ b/source/Core/ValueObject.cpp
@@ -95,7 +95,8 @@
     m_is_bitfield_for_scalar(false),
     m_is_expression_path_child(false),
     m_is_child_at_offset(false),
-    m_is_getting_summary(false)
+    m_is_getting_summary(false),
+    m_did_calculate_complete_objc_class_type(false)
 {
     m_manager->ManageObject(this);
 }
@@ -141,7 +142,8 @@
     m_is_bitfield_for_scalar(false),
     m_is_expression_path_child(false),
     m_is_child_at_offset(false),
-    m_is_getting_summary(false)
+    m_is_getting_summary(false),
+    m_did_calculate_complete_objc_class_type(false)
 {
     m_manager = new ValueObjectManager();
     m_manager->ManageObject (this);
@@ -271,6 +273,103 @@
     m_value_str.clear();
 }
 
+ClangASTType
+ValueObject::MaybeCalculateCompleteType ()
+{
+    ClangASTType ret(GetClangASTImpl(), GetClangTypeImpl());
+    
+    if (m_did_calculate_complete_objc_class_type)
+    {
+        if (m_override_type.IsValid())
+            return m_override_type;
+        else
+            return ret;
+    }
+    
+    clang_type_t ast_type(GetClangTypeImpl());
+    clang_type_t class_type;
+    bool is_pointer_type;
+    
+    if (ClangASTContext::IsObjCObjectPointerType(ast_type, &class_type))
+    {
+        is_pointer_type = true;
+    }
+    else if (ClangASTContext::IsObjCClassType(ast_type))
+    {
+        is_pointer_type = false;
+        class_type = ast_type;
+    }
+    else
+    {
+        return ret;
+    }
+    
+    m_did_calculate_complete_objc_class_type = true;
+    
+    if (!class_type)
+        return ret;
+    
+    std::string class_name;
+    
+    if (!ClangASTContext::GetObjCClassName(class_type, class_name))
+        return ret;
+    
+    ProcessSP process_sp(GetUpdatePoint().GetExecutionContextRef().GetProcessSP());
+    
+    if (!process_sp)
+        return ret;
+    
+    ObjCLanguageRuntime *objc_language_runtime(process_sp->GetObjCLanguageRuntime());
+    
+    if (!objc_language_runtime)
+        return ret;
+    
+    ConstString class_name_cs(class_name.c_str());
+    
+    TypeSP complete_objc_class_type_sp = objc_language_runtime->LookupInCompleteClassCache(class_name_cs);
+    
+    if (!complete_objc_class_type_sp)
+        return ret;
+    
+    ClangASTType complete_class(complete_objc_class_type_sp->GetClangAST(),
+                                complete_objc_class_type_sp->GetClangFullType());
+    
+    if (!ClangASTContext::GetCompleteType(complete_class.GetASTContext(), 
+                                          complete_class.GetOpaqueQualType()))
+        return ret;
+    
+    if (is_pointer_type)
+    {
+        clang_type_t pointer_type = ClangASTContext::CreatePointerType(complete_class.GetASTContext(),
+                                                                       complete_class.GetOpaqueQualType());
+        
+        m_override_type = ClangASTType(complete_class.GetASTContext(),
+                                       pointer_type);
+    }
+    else
+    {
+        m_override_type = complete_class;
+    }
+    
+    return m_override_type;
+}
+
+clang::ASTContext *
+ValueObject::GetClangAST ()
+{
+    ClangASTType type = MaybeCalculateCompleteType();
+    
+    return type.GetASTContext();
+}
+
+lldb::clang_type_t
+ValueObject::GetClangType ()
+{
+    ClangASTType type = MaybeCalculateCompleteType();
+    
+    return type.GetOpaqueQualType();
+}
+
 DataExtractor &
 ValueObject::GetDataExtractor ()
 {
diff --git a/source/Core/ValueObjectChild.cpp b/source/Core/ValueObjectChild.cpp
index eb24790..91522ba 100644
--- a/source/Core/ValueObjectChild.cpp
+++ b/source/Core/ValueObjectChild.cpp
@@ -65,7 +65,7 @@
 uint32_t
 ValueObjectChild::CalculateNumChildren()
 {
-    return ClangASTContext::GetNumChildren (GetClangAST (), m_clang_type, true);
+    return ClangASTContext::GetNumChildren (GetClangAST (), GetClangType(), true);
 }
 
 ConstString
@@ -101,7 +101,7 @@
     {
         if (parent->UpdateValueIfNeeded(false))
         {
-            m_value.SetContext(Value::eContextTypeClangType, m_clang_type);
+            m_value.SetContext(Value::eContextTypeClangType, GetClangType());
 
             // Copy the parent scalar value and the scalar value type
             m_value.GetScalar() = parent->GetValue().GetScalar();
diff --git a/source/Core/ValueObjectConstResult.cpp b/source/Core/ValueObjectConstResult.cpp
index ee82e24..dfa4cfa 100644
--- a/source/Core/ValueObjectConstResult.cpp
+++ b/source/Core/ValueObjectConstResult.cpp
@@ -275,7 +275,7 @@
 }
 
 lldb::clang_type_t
-ValueObjectConstResult::GetClangType()
+ValueObjectConstResult::GetClangTypeImpl()
 {
     return m_value.GetClangType();
 }
@@ -307,7 +307,7 @@
 }
 
 clang::ASTContext *
-ValueObjectConstResult::GetClangAST ()
+ValueObjectConstResult::GetClangASTImpl ()
 {
     return m_clang_ast;
 }
diff --git a/source/Core/ValueObjectDynamicValue.cpp b/source/Core/ValueObjectDynamicValue.cpp
index e608ce9..b336a7f 100644
--- a/source/Core/ValueObjectDynamicValue.cpp
+++ b/source/Core/ValueObjectDynamicValue.cpp
@@ -61,7 +61,7 @@
 }
 
 lldb::clang_type_t
-ValueObjectCast::GetClangType ()
+ValueObjectCast::GetClangTypeImpl ()
 {
     return m_cast_type.GetOpaqueQualType();
 }
@@ -79,7 +79,7 @@
 }
 
 clang::ASTContext *
-ValueObjectCast::GetClangAST ()
+ValueObjectCast::GetClangASTImpl ()
 {
     return m_cast_type.GetASTContext();
 }
@@ -159,7 +159,7 @@
 }
 
 lldb::clang_type_t
-ValueObjectDynamicValue::GetClangType ()
+ValueObjectDynamicValue::GetClangTypeImpl ()
 {
     if (m_type_sp)
         return m_value.GetClangType();
@@ -188,7 +188,7 @@
 }
 
 clang::ASTContext *
-ValueObjectDynamicValue::GetClangAST ()
+ValueObjectDynamicValue::GetClangASTImpl ()
 {
     const bool success = UpdateValueIfNeeded(false);
     if (success && m_type_sp)
diff --git a/source/Core/ValueObjectMemory.cpp b/source/Core/ValueObjectMemory.cpp
index 9f26a46..970cd26 100644
--- a/source/Core/ValueObjectMemory.cpp
+++ b/source/Core/ValueObjectMemory.cpp
@@ -131,7 +131,7 @@
 }
 
 lldb::clang_type_t
-ValueObjectMemory::GetClangType ()
+ValueObjectMemory::GetClangTypeImpl ()
 {
     if (m_type_sp)
         return m_type_sp->GetClangForwardType();
@@ -158,7 +158,7 @@
 }
 
 clang::ASTContext *
-ValueObjectMemory::GetClangAST ()
+ValueObjectMemory::GetClangASTImpl ()
 {
     if (m_type_sp)
         return m_type_sp->GetClangAST();
diff --git a/source/Core/ValueObjectRegister.cpp b/source/Core/ValueObjectRegister.cpp
index d96a5af..1b1b779 100644
--- a/source/Core/ValueObjectRegister.cpp
+++ b/source/Core/ValueObjectRegister.cpp
@@ -43,7 +43,7 @@
 }
 
 lldb::clang_type_t
-ValueObjectRegisterContext::GetClangType ()
+ValueObjectRegisterContext::GetClangTypeImpl ()
 {
     return NULL;
 }
@@ -62,7 +62,7 @@
 }
 
 clang::ASTContext *
-ValueObjectRegisterContext::GetClangAST ()
+ValueObjectRegisterContext::GetClangASTImpl ()
 {
     return NULL;
 }
@@ -140,7 +140,7 @@
 }
 
 lldb::clang_type_t
-ValueObjectRegisterSet::GetClangType ()
+ValueObjectRegisterSet::GetClangTypeImpl ()
 {
     return NULL;
 }
@@ -161,7 +161,7 @@
 }
 
 clang::ASTContext *
-ValueObjectRegisterSet::GetClangAST ()
+ValueObjectRegisterSet::GetClangASTImpl ()
 {
     return NULL;
 }
@@ -303,7 +303,7 @@
 }
 
 lldb::clang_type_t
-ValueObjectRegister::GetClangType ()
+ValueObjectRegister::GetClangTypeImpl ()
 {
     if (m_clang_type == NULL)
     {
@@ -337,7 +337,7 @@
 }
 
 clang::ASTContext *
-ValueObjectRegister::GetClangAST ()
+ValueObjectRegister::GetClangASTImpl ()
 {
     ExecutionContext exe_ctx (GetExecutionContextRef());
     Target *target = exe_ctx.GetTargetPtr();
diff --git a/source/Core/ValueObjectSyntheticFilter.cpp b/source/Core/ValueObjectSyntheticFilter.cpp
index 31d3fa1..1e2cea3 100644
--- a/source/Core/ValueObjectSyntheticFilter.cpp
+++ b/source/Core/ValueObjectSyntheticFilter.cpp
@@ -54,7 +54,7 @@
 }
 
 lldb::clang_type_t
-ValueObjectSynthetic::GetClangType ()
+ValueObjectSynthetic::GetClangTypeImpl ()
 {
     if (m_type_sp)
         return m_value.GetClangType();
@@ -79,7 +79,7 @@
 }
 
 clang::ASTContext *
-ValueObjectSynthetic::GetClangAST ()
+ValueObjectSynthetic::GetClangASTImpl ()
 {
     const bool success = UpdateValueIfNeeded(false);
     if (success && m_type_sp)
diff --git a/source/Core/ValueObjectVariable.cpp b/source/Core/ValueObjectVariable.cpp
index 24f189d..653b3cb 100644
--- a/source/Core/ValueObjectVariable.cpp
+++ b/source/Core/ValueObjectVariable.cpp
@@ -53,7 +53,7 @@
 }
 
 lldb::clang_type_t
-ValueObjectVariable::GetClangType ()
+ValueObjectVariable::GetClangTypeImpl ()
 {
     Type *var_type = m_variable_sp->GetType();
     if (var_type)
@@ -73,15 +73,19 @@
 
 uint32_t
 ValueObjectVariable::CalculateNumChildren()
-{
-    Type *var_type = m_variable_sp->GetType();
-    if (var_type)
-        return var_type->GetNumChildren(true);
-    return 0;
+{    
+    ClangASTType type(GetClangAST(),
+                      GetClangType());
+    
+    if (!type.IsValid())
+        return 0;
+    
+    const bool omit_empty_base_classes = true;
+    return ClangASTContext::GetNumChildren(type.GetASTContext(), type.GetOpaqueQualType(), omit_empty_base_classes);
 }
 
 clang::ASTContext *
-ValueObjectVariable::GetClangAST ()
+ValueObjectVariable::GetClangASTImpl ()
 {
     Type *var_type = m_variable_sp->GetType();
     if (var_type)
@@ -92,10 +96,13 @@
 size_t
 ValueObjectVariable::GetByteSize()
 {
-    Type *type = m_variable_sp->GetType();
-    if (type)
-        return type->GetByteSize();
-    return 0;
+    ClangASTType type(GetClangAST(),
+                      GetClangType());
+    
+    if (!type.IsValid())
+        return 0;
+    
+    return (ClangASTType::GetClangTypeBitWidth(type.GetASTContext(), type.GetOpaqueQualType()) + 7) / 8;
 }
 
 lldb::ValueType
diff --git a/source/Expression/ClangASTSource.cpp b/source/Expression/ClangASTSource.cpp
index 7cdc3f6..3376bd1 100644
--- a/source/Expression/ClangASTSource.cpp
+++ b/source/Expression/ClangASTSource.cpp
@@ -847,6 +847,63 @@
     return DeclFromParser<D>(dyn_cast<D>(parser_generic_decl.decl));
 }
 
+static bool
+FindObjCPropertyAndIvarDeclsWithOrigin (unsigned int current_id, 
+                                        NameSearchContext &context,
+                                        clang::ASTContext &ast_context,
+                                        ClangASTImporter *ast_importer,
+                                        DeclFromUser<const ObjCInterfaceDecl> &origin_iface_decl)
+{
+    lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+    if (origin_iface_decl.IsInvalid())
+        return false;
+    
+    std::string name_str = context.m_decl_name.getAsString();
+    StringRef name(name_str.c_str());
+    IdentifierInfo &name_identifier(origin_iface_decl->getASTContext().Idents.get(name));
+    
+    DeclFromUser<ObjCPropertyDecl> origin_property_decl(origin_iface_decl->FindPropertyDeclaration(&name_identifier));
+    
+    bool found = false;
+    
+    if (origin_property_decl.IsValid())
+    {
+        DeclFromParser<ObjCPropertyDecl> parser_property_decl(origin_property_decl.Import(ast_importer, ast_context));
+        if (parser_property_decl.IsValid())
+        {
+            if (log)
+            {
+                ASTDumper dumper((Decl*)parser_property_decl.decl);
+                log->Printf("  CAS::FOPD[%d] found %s", current_id, dumper.GetCString());
+            }
+            
+            context.AddNamedDecl(parser_property_decl.decl);
+            found = true;
+        }
+    }
+    
+    DeclFromUser<ObjCIvarDecl> origin_ivar_decl(origin_iface_decl->getIvarDecl(&name_identifier));
+    
+    if (origin_ivar_decl.IsValid())
+    {
+        DeclFromParser<ObjCIvarDecl> parser_ivar_decl(origin_ivar_decl.Import(ast_importer, ast_context));
+        if (parser_ivar_decl.IsValid())
+        {
+            if (log)
+            {
+                ASTDumper dumper((Decl*)parser_ivar_decl.decl);
+                log->Printf("  CAS::FOPD[%d] found %s", current_id, dumper.GetCString());
+            }
+            
+            context.AddNamedDecl(parser_ivar_decl.decl);
+            found = true;
+        }
+    }
+    
+    return found;
+}
+
 void
 ClangASTSource::FindObjCPropertyAndIvarDecls (NameSearchContext &context)
 {
@@ -857,54 +914,77 @@
     
     DeclFromParser<const ObjCInterfaceDecl> parser_iface_decl(cast<ObjCInterfaceDecl>(context.m_decl_context));
     DeclFromUser<const ObjCInterfaceDecl> origin_iface_decl(parser_iface_decl.GetOrigin(m_ast_importer));
-    
-    if (origin_iface_decl.IsInvalid())
-        return;
-    
-    std::string name_str = context.m_decl_name.getAsString();
-    StringRef name(name_str.c_str());
-    IdentifierInfo &name_identifier(origin_iface_decl->getASTContext().Idents.get(name));
+
+    ConstString class_name(parser_iface_decl->getNameAsString().c_str());
     
     if (log)
         log->Printf("ClangASTSource::FindObjCPropertyAndIvarDecls[%d] on (ASTContext*)%p for '%s.%s'",
                     current_id, 
                     m_ast_context,
                     parser_iface_decl->getNameAsString().c_str(), 
-                    name_str.c_str());
+                    context.m_decl_name.getAsString().c_str());
     
-    DeclFromUser<ObjCPropertyDecl> origin_property_decl(origin_iface_decl->FindPropertyDeclaration(&name_identifier));
+    if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id, 
+                                               context, 
+                                               *m_ast_context, 
+                                               m_ast_importer, 
+                                               origin_iface_decl))
+        return;
     
-    if (origin_property_decl.IsValid())
-    {
-        DeclFromParser<ObjCPropertyDecl> parser_property_decl(origin_property_decl.Import(m_ast_importer, *m_ast_context));
-        if (parser_property_decl.IsValid())
-        {
-            if (log)
-            {
-                ASTDumper dumper((Decl*)parser_property_decl.decl);
-                log->Printf("  CAS::FOPD[%d] found %s", current_id, dumper.GetCString());
-            }
-            
-            context.AddNamedDecl(parser_property_decl.decl);
-        }
-    }
+    if (log)
+        log->Printf("CAS::FOPD[%d] couldn't find the property on origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p, searching elsewhere...",
+                    current_id,
+                    origin_iface_decl.decl, 
+                    &origin_iface_decl->getASTContext());
     
-    DeclFromUser<ObjCIvarDecl> origin_ivar_decl(origin_iface_decl->getIvarDecl(&name_identifier));
+    SymbolContext null_sc;
+    TypeList type_list;
     
-    if (origin_ivar_decl.IsValid())
-    {
-        DeclFromParser<ObjCIvarDecl> parser_ivar_decl(origin_ivar_decl.Import(m_ast_importer, *m_ast_context));
-        if (parser_ivar_decl.IsValid())
-        {
-            if (log)
-            {
-                ASTDumper dumper((Decl*)parser_ivar_decl.decl);
-                log->Printf("  CAS::FOPD[%d] found %s", current_id, dumper.GetCString());
-            }
-            
-            context.AddNamedDecl(parser_ivar_decl.decl);
-        }
-    }
+    lldb::ProcessSP process(m_target->GetProcessSP());
+    
+    if (!process)
+        return;
+    
+    ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
+    
+    if (!language_runtime)
+        return;
+    
+    lldb::TypeSP complete_type_sp(language_runtime->LookupInCompleteClassCache(class_name));
+    
+    if (!complete_type_sp)
+        return;
+    
+    TypeFromUser complete_type = TypeFromUser(complete_type_sp->GetClangFullType(), complete_type_sp->GetClangAST());
+    lldb::clang_type_t complete_opaque_type = complete_type.GetOpaqueQualType();
+    
+    if (!complete_opaque_type)
+        return;
+    
+    const clang::Type *complete_clang_type = QualType::getFromOpaquePtr(complete_opaque_type).getTypePtr();
+    const ObjCInterfaceType *complete_interface_type = dyn_cast<ObjCInterfaceType>(complete_clang_type);
+    
+    if (!complete_interface_type)
+        return;
+    
+    DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl(complete_interface_type->getDecl());
+    
+    if (complete_iface_decl.decl == origin_iface_decl.decl)
+        return; // already checked this one
+    
+    if (log)
+        log->Printf("CAS::FOPD[%d] trying origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
+                    current_id,
+                    complete_iface_decl.decl, 
+                    &complete_iface_decl->getASTContext());
+    
+    
+    if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id, 
+                                               context, 
+                                               *m_ast_context, 
+                                               m_ast_importer, 
+                                               complete_iface_decl))
+        return;
 }
 
 typedef llvm::DenseMap <const FieldDecl *, uint64_t> FieldOffsetMap;
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 380da92..56fc593 100644
--- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -4962,6 +4962,8 @@
                                              &decl, 
                                              clang_type, 
                                              Type::eResolveStateForward));
+                    
+                    type_sp->SetIsCompleteObjCClass(is_complete_objc_class);
 
 
                     // Add our type to the unique type map so we don't
diff --git a/source/Symbol/ClangASTContext.cpp b/source/Symbol/ClangASTContext.cpp
index 9bb893c..7c744fb 100644
--- a/source/Symbol/ClangASTContext.cpp
+++ b/source/Symbol/ClangASTContext.cpp
@@ -5831,6 +5831,49 @@
     return false;
 }
 
+bool
+ClangASTContext::IsObjCObjectPointerType (lldb::clang_type_t clang_type, clang_type_t *class_type)
+{
+    if (clang_type)
+    {
+        QualType qual_type (QualType::getFromOpaquePtr(clang_type));
+        if (qual_type->isObjCObjectPointerType())
+        {
+            if (class_type)
+            {
+                *class_type = NULL;
+                
+                if (!qual_type->isObjCClassType() &&
+                    !qual_type->isObjCIdType())
+                {
+                    const ObjCObjectPointerType *obj_pointer_type = dyn_cast<ObjCObjectPointerType>(qual_type);
+                    *class_type = QualType(obj_pointer_type->getInterfaceType(), 0).getAsOpaquePtr();
+                }
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+bool
+ClangASTContext::GetObjCClassName (lldb::clang_type_t clang_type,
+                                   std::string &class_name)
+{
+    if (!clang_type)
+        return false;
+        
+    const ObjCObjectType *object_type = dyn_cast<ObjCObjectType>(QualType::getFromOpaquePtr(clang_type));
+    if (!object_type)
+        return false;
+    
+    const ObjCInterfaceDecl *interface = object_type->getInterface();
+    if (!interface)
+        return false;
+    
+    class_name = interface->getNameAsString();
+    return true;
+}
 
 bool 
 ClangASTContext::IsCharType (clang_type_t clang_type)
diff --git a/source/Symbol/Type.cpp b/source/Symbol/Type.cpp
index 0844a9e..a50c98d 100644
--- a/source/Symbol/Type.cpp
+++ b/source/Symbol/Type.cpp
@@ -20,6 +20,7 @@
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Symbol/SymbolContextScope.h"
 #include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
 #include "lldb/Symbol/Type.h"
 #include "lldb/Symbol/TypeList.h"
 
@@ -61,9 +62,10 @@
     m_encoding_uid_type (encoding_uid_type),
     m_byte_size (byte_size),
     m_decl (decl),
-    m_clang_type (clang_type),
-    m_clang_type_resolve_state (clang_type ? clang_type_resolve_state : eResolveStateUnresolved)
+    m_clang_type (clang_type)
 {
+    m_flags.clang_type_resolve_state = (clang_type ? clang_type_resolve_state : eResolveStateUnresolved);
+    m_flags.is_complete_objc_class = false;
 }
 
 Type::Type () :
@@ -76,9 +78,10 @@
     m_encoding_uid_type (eEncodingInvalid),
     m_byte_size (0),
     m_decl (),
-    m_clang_type (NULL),
-    m_clang_type_resolve_state (eResolveStateUnresolved)
+    m_clang_type (NULL)
 {
+    m_flags.clang_type_resolve_state = eResolveStateUnresolved;
+    m_flags.is_complete_objc_class = false;
 }
 
 
@@ -93,7 +96,7 @@
     m_byte_size (rhs.m_byte_size),
     m_decl (rhs.m_decl),
     m_clang_type (rhs.m_clang_type),
-    m_clang_type_resolve_state (rhs.m_clang_type_resolve_state)
+    m_flags (rhs.m_flags)
 {
 }
 
@@ -458,7 +461,7 @@
                 if (encoding_type->ResolveClangType(clang_type_resolve_state))
                 {
                     m_clang_type = encoding_type->m_clang_type;
-                    m_clang_type_resolve_state = encoding_type->m_clang_type_resolve_state;
+                    m_flags.clang_type_resolve_state = encoding_type->m_flags.clang_type_resolve_state;
                 }
                 break;
 
@@ -544,9 +547,9 @@
     }
     
     // Check if we have a forward reference to a class/struct/union/enum?
-    if (m_clang_type && m_clang_type_resolve_state < clang_type_resolve_state)
+    if (m_clang_type && m_flags.clang_type_resolve_state < clang_type_resolve_state)
     {
-        m_clang_type_resolve_state = eResolveStateFull;
+        m_flags.clang_type_resolve_state = eResolveStateFull;
         if (!ClangASTType::IsDefined (m_clang_type))
         {
             // We have a forward declaration, we need to resolve it to a complete
diff --git a/source/Target/ObjCLanguageRuntime.cpp b/source/Target/ObjCLanguageRuntime.cpp
index 00d3aa4..0076ff0 100644
--- a/source/Target/ObjCLanguageRuntime.cpp
+++ b/source/Target/ObjCLanguageRuntime.cpp
@@ -14,6 +14,7 @@
 #include "lldb/Symbol/ClangASTContext.h"
 #include "lldb/Symbol/Type.h"
 #include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -94,6 +95,84 @@
     return TypeAndOrName ();
 }
 
+lldb::TypeSP
+ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name)
+{
+    CompleteClassMap::iterator complete_class_iter = m_complete_class_cache.find(name);
+    
+    if (complete_class_iter != m_complete_class_cache.end())
+    {
+        TypeSP ret(complete_class_iter->second);
+        
+        if (!ret)
+            m_complete_class_cache.erase(name);
+        else
+            return TypeSP(complete_class_iter->second);
+    }
+    
+    ModuleList &modules = m_process->GetTarget().GetImages();
+    
+    SymbolContextList sc_list;
+    
+    modules.FindSymbolsWithNameAndType(name, eSymbolTypeObjCClass, sc_list);
+    
+    if (sc_list.GetSize() == 0)
+        return TypeSP();
+    
+    SymbolContext sc;
+    
+    sc_list.GetContextAtIndex(0, sc);
+    
+    ModuleSP module_sp(sc.module_sp);
+    
+    if (!module_sp)
+        return TypeSP();
+    
+    const SymbolContext null_sc;
+    const ClangNamespaceDecl *null_namespace_decl = NULL;
+    const bool append = false;
+    const uint32_t max_matches = UINT32_MAX;
+    TypeList types;
+    
+    module_sp->FindTypes(null_sc, 
+                         name,
+                         null_namespace_decl,
+                         append, 
+                         max_matches, 
+                         types);
+    
+    if (types.GetSize() == 1)
+    {
+        TypeSP candidate_type = types.GetTypeAtIndex(0);
+        
+        if (ClangASTContext::IsObjCClassType(candidate_type->GetClangForwardType()))
+        {
+            m_complete_class_cache[name] = TypeWP(candidate_type);
+            return candidate_type;
+        }
+        else
+        {
+            return TypeSP();
+        }
+    }
+    
+    for (uint32_t ti = 0, te = types.GetSize();
+         ti < te;
+         ++ti)
+    {
+        TypeSP candidate_type = types.GetTypeAtIndex(ti);
+        
+        if (candidate_type->IsCompleteObjCClass() &&
+            ClangASTContext::IsObjCClassType(candidate_type->GetClangForwardType()))
+        {
+            m_complete_class_cache[name] = TypeWP(candidate_type);
+            return candidate_type;                                       
+        }
+    }
+    
+    return TypeSP();
+}
+
 size_t
 ObjCLanguageRuntime::GetByteOffsetForIvar (ClangASTType &parent_qual_type, const char *ivar_name)
 {
diff --git a/test/lang/objc/hidden-ivars/InternalDefiner.h b/test/lang/objc/hidden-ivars/InternalDefiner.h
new file mode 100644
index 0000000..b9b5470
--- /dev/null
+++ b/test/lang/objc/hidden-ivars/InternalDefiner.h
@@ -0,0 +1,10 @@
+#import <Foundation/Foundation.h>
+
+@interface InternalDefiner : NSObject {
+@public
+    int foo;
+}
+
+-(int)setBarTo:(int)newBar;
+
+@end
diff --git a/test/lang/objc/hidden-ivars/InternalDefiner.m b/test/lang/objc/hidden-ivars/InternalDefiner.m
new file mode 100644
index 0000000..97536b1
--- /dev/null
+++ b/test/lang/objc/hidden-ivars/InternalDefiner.m
@@ -0,0 +1,18 @@
+#import "InternalDefiner.h"
+
+@interface InternalDefiner () {
+    int bar;
+}
+
+@end
+
+@implementation InternalDefiner
+
+-(int)setBarTo:(int)newBar
+{
+    int oldBar = bar;
+    bar = newBar;
+    return oldBar;
+}
+
+@end
diff --git a/test/lang/objc/hidden-ivars/Makefile b/test/lang/objc/hidden-ivars/Makefile
new file mode 100644
index 0000000..e99c30c
--- /dev/null
+++ b/test/lang/objc/hidden-ivars/Makefile
@@ -0,0 +1,9 @@
+LEVEL = ../../../make
+
+DYLIB_NAME := libInternalDefiner
+DYLIB_OBJC_SOURCES := InternalDefiner.m
+OBJC_SOURCES := main.m
+
+LDFLAGS = -framework Foundation
+
+include $(LEVEL)/Makefile.rules
diff --git a/test/lang/objc/hidden-ivars/TestHiddenIvars.py b/test/lang/objc/hidden-ivars/TestHiddenIvars.py
new file mode 100644
index 0000000..f0bb94b
--- /dev/null
+++ b/test/lang/objc/hidden-ivars/TestHiddenIvars.py
@@ -0,0 +1,77 @@
+"""Test that hidden ivars in a shared library are visible from the main executable."""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+
+class HiddenIvarsTestCase(TestBase):
+
+    mydir = os.path.join("lang", "objc", "hidden-ivars")
+
+    def test_expr_with_dsym(self):
+        self.buildDsym()
+        self.expr()
+
+    def test_expr_with_dwarf(self):
+        self.buildDwarf()
+        self.expr()
+
+    def test_frame_variable_with_dsym(self):
+        self.buildDsym()
+        self.frame_var()
+
+    def test_frame_variable_with_dwarf(self):
+        self.buildDwarf()
+        self.frame_var()
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line number to break inside main().
+        self.line = line_number('main.m', '// Set breakpoint 0 here.')
+
+    def common_setup(self):
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        # Break inside the foo function which takes a bar_ptr argument.
+        self.expect("breakpoint set -f main.m -l %d" % self.line, BREAKPOINT_CREATED,
+            startstr = "Breakpoint created")
+
+        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'])
+
+        # The breakpoint should have a hit count of 1.
+        self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
+            substrs = [' resolved, hit count = 1'])
+
+    def expr(self):
+        self.common_setup()
+
+        # This should display correctly.
+        self.expect("expression (i->bar)", VARIABLES_DISPLAYED_CORRECTLY,
+            substrs = ["= 3"])
+            
+        self.expect("expression (*i)", VARIABLES_DISPLAYED_CORRECTLY,
+            substrs = ["foo = 0", "bar = 3"])
+
+    def frame_var(self):
+        self.common_setup()
+
+        # This should display correctly.
+        self.expect("frame variable i->bar", VARIABLES_DISPLAYED_CORRECTLY,
+            substrs = ["= 3"])
+            
+        self.expect("frame variable *i", VARIABLES_DISPLAYED_CORRECTLY,
+            substrs = ["foo = 0", "bar = 3"])
+                       
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()
diff --git a/test/lang/objc/hidden-ivars/main.m b/test/lang/objc/hidden-ivars/main.m
new file mode 100644
index 0000000..0b21959
--- /dev/null
+++ b/test/lang/objc/hidden-ivars/main.m
@@ -0,0 +1,18 @@
+#import <Foundation/Foundation.h>
+#import "InternalDefiner.h"
+
+int main(int argc, const char * argv[])
+{
+
+    @autoreleasepool {
+        
+        InternalDefiner *i = [InternalDefiner alloc];
+        
+        [i setBarTo:3];
+        
+        printf("ivar value = %d", i->foo); // Set breakpoint 0 here.
+        
+    }
+    return 0;
+}
+
diff --git a/test/make/Makefile.rules b/test/make/Makefile.rules
index 238acb7..53beb1e 100644
--- a/test/make/Makefile.rules
+++ b/test/make/Makefile.rules
@@ -95,6 +95,10 @@
 	DYLIB_OBJECTS +=$(strip $(DYLIB_C_SOURCES:.c=.o))
 endif
 
+ifneq "$(strip $(DYLIB_OBJC_SOURCES))" ""
+	DYLIB_OBJECTS +=$(strip $(DYLIB_OBJC_SOURCES:.m=.o))
+endif
+
 ifneq "$(strip $(DYLIB_CXX_SOURCES))" ""
     DYLIB_OBJECTS +=$(strip $(DYLIB_CXX_SOURCES:.cpp=.o))
     CXX = $(call cxx_compiler,$(CC))