diff options
author | Sean Callanan <scallanan@apple.com> | 2011-11-15 02:11:17 +0000 |
---|---|---|
committer | Sean Callanan <scallanan@apple.com> | 2011-11-15 02:11:17 +0000 |
commit | d5c17edb04b4260fbbaca8e9a9b5e18f86964799 (patch) | |
tree | e817fa4ab4bdc539b7b8c3d1fb182c14a2ec0353 | |
parent | 29cdcda80d45a58eefbd488980965048efba2b8a (diff) | |
download | bcm5719-llvm-d5c17edb04b4260fbbaca8e9a9b5e18f86964799.tar.gz bcm5719-llvm-d5c17edb04b4260fbbaca8e9a9b5e18f86964799.zip |
Pulled in a new version of LLVM/Clang to solve a variety
of problems with Objective-C object completion. To go
along with the LLVM/Clang-side fixes, we have a variety
of Objective-C improvements.
Fixes include:
- It is now possible to run expressions when stopped in
an Objective-C class method and have "self" act just
like "self" would act in the class method itself (i.e.,
[self classMethod] works without casting the return
type if debug info is present). To accomplish this,
the expression masquerades as a class method added by
a category.
- Objective-C objects can now provide methods and
properties and methods to Clang on demand (i.e., the
ASTImporter sets hasExternalVisibleDecls on Objective-C
interface objects).
- Objective-C built-in types, which had long been a bone
of contention (should we be using "id"? "id*"?), are
now fetched correctly using accessor functions on
ClangASTContext. We inhibit searches for them in the
debug information.
There are also a variety of logging fixes, and I made two
changes to the test suite:
- Enabled a test case for Objective-C properties in the
current translation unit.
- Added a test case for calling Objective-C class methods
when stopped in a class method.
llvm-svn: 144607
-rw-r--r-- | lldb/include/lldb/Expression/ASTDumper.h | 2 | ||||
-rw-r--r-- | lldb/include/lldb/Expression/ClangASTSource.h | 13 | ||||
-rw-r--r-- | lldb/include/lldb/Expression/ClangUserExpression.h | 1 | ||||
-rw-r--r-- | lldb/include/lldb/Expression/ExpressionSourceCode.h | 3 | ||||
-rw-r--r-- | lldb/scripts/build-llvm.pl | 4 | ||||
-rw-r--r-- | lldb/source/Expression/ASTDumper.cpp | 2 | ||||
-rw-r--r-- | lldb/source/Expression/ClangASTSource.cpp | 61 | ||||
-rw-r--r-- | lldb/source/Expression/ClangExpressionDeclMap.cpp | 71 | ||||
-rw-r--r-- | lldb/source/Expression/ClangUserExpression.cpp | 8 | ||||
-rw-r--r-- | lldb/source/Expression/ExpressionSourceCode.cpp | 53 | ||||
-rw-r--r-- | lldb/source/Symbol/ClangASTContext.cpp | 8 | ||||
-rw-r--r-- | lldb/source/Symbol/ClangASTImporter.cpp | 18 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-property/TestObjCProperty.py | 10 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-static-method/TestObjCStaticMethod.py | 5 | ||||
-rw-r--r-- | lldb/test/lang/objc/objc-static-method/static.m | 6 |
15 files changed, 197 insertions, 68 deletions
diff --git a/lldb/include/lldb/Expression/ASTDumper.h b/lldb/include/lldb/Expression/ASTDumper.h index ccf6ab05661..bac2ec18ee8 100644 --- a/lldb/include/lldb/Expression/ASTDumper.h +++ b/lldb/include/lldb/Expression/ASTDumper.h @@ -22,7 +22,7 @@ class ASTDumper public: ASTDumper (clang::Decl *decl); ASTDumper (clang::DeclContext *decl_ctx); - ASTDumper (clang::Type *type); + ASTDumper (const clang::Type *type); ASTDumper (clang::QualType type); ASTDumper (lldb::clang_type_t type); diff --git a/lldb/include/lldb/Expression/ClangASTSource.h b/lldb/include/lldb/Expression/ClangASTSource.h index 030bc4547a2..2d1c7562ee4 100644 --- a/lldb/include/lldb/Expression/ClangASTSource.h +++ b/lldb/include/lldb/Expression/ClangASTSource.h @@ -289,7 +289,18 @@ protected: //------------------------------------------------------------------ void FindObjCMethodDecls (NameSearchContext &context); - + + //------------------------------------------------------------------ + /// Find all Objective-C properties with a given name. + /// + /// @param[in] context + /// The NameSearchContext that can construct Decls for this name. + /// Its m_decl_name contains the name and its m_decl_context + /// is the containing object. + //------------------------------------------------------------------ + void + FindObjCPropertyDecls (NameSearchContext &context); + //------------------------------------------------------------------ /// A wrapper for ClangASTContext::CopyType that sets a flag that /// indicates that we should not respond to queries during import. diff --git a/lldb/include/lldb/Expression/ClangUserExpression.h b/lldb/include/lldb/Expression/ClangUserExpression.h index c340e4bc84c..9e57eedaec5 100644 --- a/lldb/include/lldb/Expression/ClangUserExpression.h +++ b/lldb/include/lldb/Expression/ClangUserExpression.h @@ -356,6 +356,7 @@ private: bool m_cplusplus; ///< True if the expression is compiled as a C++ member function (true if it was parsed when exe_ctx was in a C++ method). bool m_objectivec; ///< True if the expression is compiled as an Objective-C method (true if it was parsed when exe_ctx was in an Objective-C method). + bool m_static_method; ///< True if the expression is compiled as a static (or class) method (currently true if it was parsed when exe_ctx was in an Objective-C class method). bool m_needs_object_ptr; ///< True if "this" or "self" must be looked up and passed in. False if the expression doesn't really use them and they can be NULL. bool m_const_object; ///< True if "this" is const. Target *m_target; ///< The target for storing persistent data like types and variables. diff --git a/lldb/include/lldb/Expression/ExpressionSourceCode.h b/lldb/include/lldb/Expression/ExpressionSourceCode.h index bafb7442e2c..7e908fb6951 100644 --- a/lldb/include/lldb/Expression/ExpressionSourceCode.h +++ b/lldb/include/lldb/Expression/ExpressionSourceCode.h @@ -50,7 +50,8 @@ public: bool GetText (std::string &text, lldb::LanguageType wrapping_language, - bool const_object) const; + bool const_object, + bool static_method) const; private: ExpressionSourceCode (const char *name, diff --git a/lldb/scripts/build-llvm.pl b/lldb/scripts/build-llvm.pl index 44c45cdd792..def2609889a 100644 --- a/lldb/scripts/build-llvm.pl +++ b/lldb/scripts/build-llvm.pl @@ -21,8 +21,8 @@ our ($llvm_clang_basename, $llvm_clang_dirname) = fileparse ($llvm_clang_outfile our $llvm_configuration = $ENV{LLVM_CONFIGURATION}; -our $llvm_revision = "144393"; -our $clang_revision = "144393"; +our $llvm_revision = "144573"; +our $clang_revision = "144573"; our $SRCROOT = "$ENV{SRCROOT}"; our $llvm_dstroot_zip = "$SRCROOT/llvm.zip"; diff --git a/lldb/source/Expression/ASTDumper.cpp b/lldb/source/Expression/ASTDumper.cpp index 1c819b1ff4c..a82a892bc79 100644 --- a/lldb/source/Expression/ASTDumper.cpp +++ b/lldb/source/Expression/ASTDumper.cpp @@ -63,7 +63,7 @@ ASTDumper::ASTDumper (clang::DeclContext *decl_ctx) decl_ctx->setHasExternalVisibleStorage(has_external_visible_storage); } -ASTDumper::ASTDumper (clang::Type *type) +ASTDumper::ASTDumper (const clang::Type *type) { m_dump = clang::QualType(type, 0).getAsString(); } diff --git a/lldb/source/Expression/ClangASTSource.cpp b/lldb/source/Expression/ClangASTSource.cpp index c62db70589b..a2597ba81cc 100644 --- a/lldb/source/Expression/ClangASTSource.cpp +++ b/lldb/source/Expression/ClangASTSource.cpp @@ -311,6 +311,10 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context) current_id); } } + else if (const ObjCInterfaceDecl *interface_decl = dyn_cast<ObjCInterfaceDecl>(context.m_decl_context)) + { + FindObjCPropertyDecls(context); + } else if (!isa<TranslationUnitDecl>(context.m_decl_context)) { // we shouldn't be getting FindExternalVisibleDecls calls for these @@ -568,6 +572,63 @@ ClangASTSource::FindObjCMethodDecls (NameSearchContext &context) } } +void +ClangASTSource::FindObjCPropertyDecls (NameSearchContext &context) +{ + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + static unsigned int invocation_id = 0; + unsigned int current_id = invocation_id++; + + const ObjCInterfaceDecl *iface_decl = cast<ObjCInterfaceDecl>(context.m_decl_context); + Decl *orig_decl; + ASTContext *orig_ast_ctx; + + m_ast_importer->ResolveDeclOrigin(iface_decl, &orig_decl, &orig_ast_ctx); + + if (!orig_decl) + return; + + ObjCInterfaceDecl *orig_iface_decl = dyn_cast<ObjCInterfaceDecl>(orig_decl); + + if (!orig_iface_decl) + return; + + if (!ClangASTContext::GetCompleteDecl(orig_ast_ctx, orig_iface_decl)) + return; + + std::string property_name_str = context.m_decl_name.getAsString(); + StringRef property_name(property_name_str.c_str()); + ObjCPropertyDecl *property_decl = orig_iface_decl->FindPropertyDeclaration(&orig_ast_ctx->Idents.get(property_name)); + + if (log) + log->Printf("ClangASTSource::FindObjCPropertyDecls[%d] for property '%s.%s'", + current_id, + iface_decl->getNameAsString().c_str(), + property_name_str.c_str()); + + if (!property_decl) + return; + + Decl *copied_decl = m_ast_importer->CopyDecl(orig_ast_ctx, property_decl); + + if (!copied_decl) + return; + + ObjCPropertyDecl *copied_property_decl = dyn_cast<ObjCPropertyDecl>(copied_decl); + + if (!copied_property_decl) + return; + + if (log) + { + ASTDumper dumper((Decl*)copied_property_decl); + log->Printf(" CAS::FOPD[%d] found %s", current_id, dumper.GetCString()); + } + + context.AddNamedDecl(copied_property_decl); +} + void ClangASTSource::CompleteNamespaceMap (ClangASTImporter::NamespaceMapSP &namespace_map, const ConstString &name, diff --git a/lldb/source/Expression/ClangExpressionDeclMap.cpp b/lldb/source/Expression/ClangExpressionDeclMap.cpp index 6e62c29fd05..4299220e45a 100644 --- a/lldb/source/Expression/ClangExpressionDeclMap.cpp +++ b/lldb/source/Expression/ClangExpressionDeclMap.cpp @@ -1105,13 +1105,13 @@ ClangExpressionDeclMap::GetObjectPointer if (frame == NULL || process == NULL || target == NULL) { - err.SetErrorString("Couldn't load 'this' because the context is incomplete"); + err.SetErrorStringWithFormat("Couldn't load '%s' because the context is incomplete", object_name.AsCString()); return false; } if (!m_struct_vars->m_object_pointer_type.GetOpaqueQualType()) { - err.SetErrorString("Couldn't load 'this' because its type is unknown"); + err.SetErrorStringWithFormat("Couldn't load '%s' because its type is unknown", object_name.AsCString()); return false; } @@ -1121,7 +1121,7 @@ ClangExpressionDeclMap::GetObjectPointer if (!object_ptr_var) { - err.SetErrorStringWithFormat("Couldn't find '%s' with appropriate type in scope", object_name.GetCString()); + err.SetErrorStringWithFormat("Couldn't find '%s' with appropriate type in scope", object_name.AsCString()); return false; } @@ -2224,12 +2224,7 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context) current_id); } } - else if (!isa<TranslationUnitDecl>(context.m_decl_context)) - { - // we shouldn't be getting FindExternalVisibleDecls calls for these - return; - } - else + else if (isa<TranslationUnitDecl>(context.m_decl_context)) { ClangNamespaceDecl namespace_decl; @@ -2342,12 +2337,47 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context, if (!frame) return; + + SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction); - VariableList *vars = frame->GetVariableList(false); + if (!sym_ctx.function) + return; - if (!vars) + clang::DeclContext *decl_context; + + if (sym_ctx.block && sym_ctx.block->GetInlinedFunctionInfo()) + decl_context = sym_ctx.block->GetClangDeclContextForInlinedFunction(); + else + decl_context = sym_ctx.function->GetClangDeclContext(); + + if (!decl_context) return; + clang::ObjCMethodDecl *method_decl = llvm::dyn_cast<clang::ObjCMethodDecl>(decl_context); + + if (!method_decl) + return; + + ObjCInterfaceDecl* self_interface = method_decl->getClassInterface(); + + if (!self_interface) + return; + + const clang::Type *interface_type = self_interface->getTypeForDecl(); + + TypeFromUser class_user_type(QualType(interface_type, 0).getAsOpaquePtr(), + &method_decl->getASTContext()); + + if (log) + { + ASTDumper ast_dumper(interface_type); + log->Printf(" FEVD[%u] Adding type for $__lldb_objc_class: %s", current_id, ast_dumper.GetCString()); + } + + AddOneType(context, class_user_type, current_id, false); + + VariableList *vars = frame->GetVariableList(false); + lldb::VariableSP self_var = vars->FindVariable(ConstString("self")); if (!self_var || @@ -2364,25 +2394,6 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context, self_type->GetClangAST()); m_struct_vars->m_object_pointer_type = self_user_type; - - void *pointer_target_type = NULL; - - if (!ClangASTContext::IsPointerType(self_user_type.GetOpaqueQualType(), - &pointer_target_type) - || pointer_target_type == NULL) - return; - - TypeFromUser class_user_type(pointer_target_type, - self_type->GetClangAST()); - - if (log) - { - ASTDumper ast_dumper(pointer_target_type); - log->Printf(" FEVD[%u] Adding type for $__lldb_objc_class: %s", current_id, ast_dumper.GetCString()); - } - - AddOneType(context, class_user_type, current_id, false); - return; } diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index 25eb8c4bc13..4ae34a38d58 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -56,6 +56,7 @@ ClangUserExpression::ClangUserExpression (const char *expr, m_objectivec (false), m_needs_object_ptr (false), m_const_object (false), + m_static_method(false), m_target (NULL), m_evaluated_statically (false), m_const_result () @@ -167,7 +168,7 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err) } else if (clang::ObjCMethodDecl *method_decl = llvm::dyn_cast<clang::ObjCMethodDecl>(decl_context)) { - if (m_allow_objc && method_decl->isInstanceMethod()) + if (m_allow_objc) { VariableList *vars = frame->GetVariableList(false); @@ -193,6 +194,9 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err) m_objectivec = true; m_needs_object_ptr = true; + + if (!method_decl->isInstanceMethod()) + m_static_method = true; } } } @@ -274,7 +278,7 @@ ClangUserExpression::Parse (Stream &error_stream, else lang_type = lldb::eLanguageTypeC; - if (!source_code->GetText(m_transformed_text, lang_type, m_const_object)) + if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_static_method)) { error_stream.PutCString ("error: couldn't construct expression body"); return false; diff --git a/lldb/source/Expression/ExpressionSourceCode.cpp b/lldb/source/Expression/ExpressionSourceCode.cpp index 4b749b5c86d..b1719b34c53 100644 --- a/lldb/source/Expression/ExpressionSourceCode.cpp +++ b/lldb/source/Expression/ExpressionSourceCode.cpp @@ -13,7 +13,7 @@ using namespace lldb_private; -bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object) const +bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object, bool static_method) const { if (m_wrap) { @@ -59,21 +59,42 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi m_body.c_str()); break; case lldb::eLanguageTypeObjC: - wrap_stream.Printf("%s \n" - "typedef unsigned short unichar; \n" - "@interface $__lldb_objc_class ($__lldb_category) \n" - "-(void)%s:(void *)$__lldb_arg; \n" - "@end \n" - "@implementation $__lldb_objc_class ($__lldb_category) \n" - "-(void)%s:(void *)$__lldb_arg \n" - "{ \n" - " %s; \n" - "} \n" - "@end \n", - m_prefix.c_str(), - m_name.c_str(), - m_name.c_str(), - m_body.c_str()); + if (static_method) + { + wrap_stream.Printf("%s \n" + "typedef unsigned short unichar; \n" + "@interface $__lldb_objc_class ($__lldb_category) \n" + "+(void)%s:(void *)$__lldb_arg; \n" + "@end \n" + "@implementation $__lldb_objc_class ($__lldb_category) \n" + "+(void)%s:(void *)$__lldb_arg \n" + "{ \n" + " %s; \n" + "} \n" + "@end \n", + m_prefix.c_str(), + m_name.c_str(), + m_name.c_str(), + m_body.c_str()); + } + else + { + wrap_stream.Printf("%s \n" + "typedef unsigned short unichar; \n" + "@interface $__lldb_objc_class ($__lldb_category) \n" + "-(void)%s:(void *)$__lldb_arg; \n" + "@end \n" + "@implementation $__lldb_objc_class ($__lldb_category) \n" + "-(void)%s:(void *)$__lldb_arg \n" + "{ \n" + " %s; \n" + "} \n" + "@end \n", + m_prefix.c_str(), + m_name.c_str(), + m_name.c_str(), + m_body.c_str()); + } break; } diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp index d7e1ddff8c6..fe19feaab61 100644 --- a/lldb/source/Symbol/ClangASTContext.cpp +++ b/lldb/source/Symbol/ClangASTContext.cpp @@ -931,19 +931,19 @@ ClangASTContext::GetBuiltInType_bool() clang_type_t ClangASTContext::GetBuiltInType_objc_id() { - return getASTContext()->getPointerType(getASTContext()->ObjCBuiltinIdTy).getAsOpaquePtr(); + return getASTContext()->getObjCIdType().getAsOpaquePtr(); } clang_type_t ClangASTContext::GetBuiltInType_objc_Class() { - return getASTContext()->getPointerType(getASTContext()->ObjCBuiltinClassTy).getAsOpaquePtr(); + return getASTContext()->getObjCClassType().getAsOpaquePtr(); } clang_type_t ClangASTContext::GetBuiltInType_objc_selector() { - return getASTContext()->getPointerType(getASTContext()->ObjCBuiltinSelTy).getAsOpaquePtr(); + return getASTContext()->getObjCSelType().getAsOpaquePtr(); } clang_type_t @@ -4694,7 +4694,7 @@ ClangASTContext::CompleteTagDeclarationDefinition (clang_type_t clang_type) { ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); - class_interface_decl->setForwardDecl(false); + class_interface_decl->completedForwardDecl(); } const EnumType *enum_type = dyn_cast<EnumType>(qual_type.getTypePtr()); diff --git a/lldb/source/Symbol/ClangASTImporter.cpp b/lldb/source/Symbol/ClangASTImporter.cpp index ef0dcfe4c1d..92c2325dd40 100644 --- a/lldb/source/Symbol/ClangASTImporter.cpp +++ b/lldb/source/Symbol/ClangASTImporter.cpp @@ -186,14 +186,26 @@ clang::Decl to_namespace_decl->setHasExternalVisibleStorage(); } - if (isa<ObjCInterfaceDecl>(from)) + if (ObjCInterfaceDecl *from_interface_decl = dyn_cast<ObjCInterfaceDecl>(from)) { ObjCInterfaceDecl *to_interface_decl = dyn_cast<ObjCInterfaceDecl>(to); + to_interface_decl->setHasExternalLexicalStorage(); to_interface_decl->setHasExternalVisibleStorage(); - if (!to_interface_decl->isForwardDecl()) - to_interface_decl->setExternallyCompleted(); + if (to_interface_decl->isForwardDecl()) + to_interface_decl->completedForwardDecl(); + + to_interface_decl->setExternallyCompleted(); + + if (log) + log->Printf(" [ClangASTImporter] Imported %p, a %s named %s%s%s%s", + to, + ((clang::Decl*)from_interface_decl)->getDeclKindName(), + from_interface_decl->getName().str().c_str(), + (to_interface_decl->hasExternalLexicalStorage() ? " Lexical" : ""), + (to_interface_decl->hasExternalVisibleStorage() ? " Visible" : ""), + (to_interface_decl->isForwardDecl() ? " Forward" : "")); } return clang::ASTImporter::Imported(from, to); diff --git a/lldb/test/lang/objc/objc-property/TestObjCProperty.py b/lldb/test/lang/objc/objc-property/TestObjCProperty.py index fbcb79560d3..8dd108dbff8 100644 --- a/lldb/test/lang/objc/objc-property/TestObjCProperty.py +++ b/lldb/test/lang/objc/objc-property/TestObjCProperty.py @@ -114,13 +114,9 @@ class ObjCDynamicValueTestCase(TestBase): self.assertTrue (backing_value.IsValid()) self.assertTrue (backed_value.GetValueAsUnsigned (12345) == backing_value.GetValueAsUnsigned(23456)) - # - # This doesn't work correctly yet, because the clang Sema::HandleExprPropertyRefExpr - # doesn't complete the class before looking up the property. - # - #unbacked_value = frame.EvaluateExpression("mine.unbackedInt", False) - #unbacked_error = unbacked_value.GetError() - #self.assertTrue (unbacked_error.Success()) + unbacked_value = frame.EvaluateExpression("mine.unbackedInt", False) + unbacked_error = unbacked_value.GetError() + self.assertTrue (unbacked_error.Success()) if __name__ == '__main__': import atexit diff --git a/lldb/test/lang/objc/objc-static-method/TestObjCStaticMethod.py b/lldb/test/lang/objc/objc-static-method/TestObjCStaticMethod.py index 7e457f6e9d8..eeac1c53228 100644 --- a/lldb/test/lang/objc/objc-static-method/TestObjCStaticMethod.py +++ b/lldb/test/lang/objc/objc-static-method/TestObjCStaticMethod.py @@ -65,6 +65,11 @@ class TestObjCStaticMethod(TestBase): sel_name = cmd_value.GetSummary() self.assertTrue (sel_name == "\"doSomethingWithString:\"", "Got the right value for the selector as string.") + cmd_value = frame.EvaluateExpression ("[self doSomethingElseWithString:string]") + self.assertTrue (cmd_value.IsValid()) + string_length = cmd_value.GetValueAsUnsigned() + self.assertTrue (string_length == 27, "Got the right value from another class method on the same class.") + if __name__ == '__main__': import atexit lldb.SBDebugger.Initialize() diff --git a/lldb/test/lang/objc/objc-static-method/static.m b/lldb/test/lang/objc/objc-static-method/static.m index a069c1502ad..ec7b2ef6719 100644 --- a/lldb/test/lang/objc/objc-static-method/static.m +++ b/lldb/test/lang/objc/objc-static-method/static.m @@ -11,6 +11,12 @@ NSLog (@"String is: %@.", string); // Set breakpoint here. } ++(int) doSomethingElseWithString: (NSString *) string +{ + NSLog (@"String is still: %@.", string); + return [string length]; +} + -(void) doSomethingWithNothing { } |