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/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)
 {