From 5540094ccdae828dc0ba970ab4f6cb836cb50c04 Mon Sep 17 00:00:00 2001 From: Sean Callanan Date: Fri, 2 Nov 2012 17:09:58 +0000 Subject: [PATCH] Extra safeguards to ensure that we never query the runtime if we have complete debug information for a class. Also made the Objective-C language runtime return NULL when asked for the complete debug information (i.e., information from DWARF, not information from the runtime) if that information isn't present. It used to return a non-authoritative version, which made it hard for clients to determine whether complete debug information was available. llvm-svn: 167299 --- lldb/source/Expression/ClangASTSource.cpp | 276 ++++++++++++--------- lldb/source/Target/ObjCLanguageRuntime.cpp | 11 - 2 files changed, 156 insertions(+), 131 deletions(-) diff --git a/lldb/source/Expression/ClangASTSource.cpp b/lldb/source/Expression/ClangASTSource.cpp index ef84b5033f48..e238303278cf 100644 --- a/lldb/source/Expression/ClangASTSource.cpp +++ b/lldb/source/Expression/ClangASTSource.cpp @@ -693,6 +693,63 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context, } while(0); } +template class TaggedASTDecl { +public: + TaggedASTDecl() : decl(NULL) { } + TaggedASTDecl(D *_decl) : decl(_decl) { } + bool IsValid() const { return (decl != NULL); } + bool IsInvalid() const { return !IsValid(); } + D *operator->() const { return decl; } + D *decl; +}; + +template class TD, class D1> +TD +DynCast(TD source) +{ + return TD (dyn_cast(source.decl)); +} + +template class DeclFromParser; +template class DeclFromUser; + +template class DeclFromParser : public TaggedASTDecl { +public: + DeclFromParser() : TaggedASTDecl() { } + DeclFromParser(D *_decl) : TaggedASTDecl(_decl) { } + + DeclFromUser GetOrigin(ClangASTImporter *importer); +}; + +template class DeclFromUser : public TaggedASTDecl { +public: + DeclFromUser() : TaggedASTDecl() { } + DeclFromUser(D *_decl) : TaggedASTDecl(_decl) { } + + DeclFromParser Import(ClangASTImporter *importer, ASTContext &dest_ctx); +}; + +template +DeclFromUser +DeclFromParser::GetOrigin(ClangASTImporter *importer) +{ + DeclFromUser <> origin_decl; + importer->ResolveDeclOrigin(this->decl, &origin_decl.decl, NULL); + if (origin_decl.IsInvalid()) + return DeclFromUser(); + return DeclFromUser(dyn_cast(origin_decl.decl)); +} + +template +DeclFromParser +DeclFromUser::Import(ClangASTImporter *importer, ASTContext &dest_ctx) +{ + DeclFromParser <> parser_generic_decl(importer->CopyDecl(&dest_ctx, &this->decl->getASTContext(), this->decl)); + if (parser_generic_decl.IsInvalid()) + return DeclFromParser(); + return DeclFromParser(dyn_cast(parser_generic_decl.decl)); +} + static void FindObjCMethodDeclsWithOrigin (unsigned int current_id, NameSearchContext &context, @@ -807,7 +864,7 @@ ClangASTSource::FindObjCMethodDecls (NameSearchContext &context) original_interface_decl, m_ast_context, m_ast_importer, - "in debug info"); + "at origin"); } while (0); StreamString ss; @@ -964,117 +1021,93 @@ ClangASTSource::FindObjCMethodDecls (NameSearchContext &context) if (log) { ASTDumper dumper((Decl*)copied_method_decl); - log->Printf(" CAS::FOMD[%d] found (in debug info) %s", current_id, dumper.GetCString()); + log->Printf(" CAS::FOMD[%d] found (in symbols) %s", current_id, dumper.GetCString()); } context.AddNamedDecl(copied_method_decl); } } + + return; } - else + + // Try the debug information. + + do { - do - { - // We need to look at the runtime. - - lldb::ProcessSP process(m_target->GetProcessSP()); - - if (!process) - break; - - ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime()); - - TypeVendor *type_vendor = language_runtime->GetTypeVendor(); - - if (!type_vendor) - break; - - ConstString interface_name(interface_decl->getNameAsString().c_str()); - bool append = false; - uint32_t max_matches = 1; - std::vector types; - - if (!type_vendor->FindTypes(interface_name, - append, - max_matches, - types)) - break; - - const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr(); - - const ObjCInterfaceType *runtime_interface_type = dyn_cast(runtime_clang_type); - - if (!runtime_interface_type) - break; - - ObjCInterfaceDecl *runtime_interface_decl = runtime_interface_type->getDecl(); - - FindObjCMethodDeclsWithOrigin(current_id, - context, - runtime_interface_decl, - m_ast_context, - m_ast_importer, - "in runtime"); - } - while(0); + ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(const_cast(interface_decl)); + + if (!complete_interface_decl) + break; + + // We found the complete interface. The runtime never needs to be queried in this scenario. + + DeclFromUser complete_iface_decl(complete_interface_decl); + + if (complete_interface_decl == interface_decl) + break; // already checked this one + + if (log) + log->Printf("CAS::FOPD[%d] trying origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p...", + current_id, + complete_interface_decl, + &complete_iface_decl->getASTContext()); + + FindObjCMethodDeclsWithOrigin(current_id, + context, + complete_interface_decl, + m_ast_context, + m_ast_importer, + "in debug info"); + + return; } -} - -template class TaggedASTDecl { -public: - TaggedASTDecl() : decl(NULL) { } - TaggedASTDecl(D *_decl) : decl(_decl) { } - bool IsValid() const { return (decl != NULL); } - bool IsInvalid() const { return !IsValid(); } - D *operator->() const { return decl; } - D *decl; -}; - -template class TD, class D1> -TD -DynCast(TD source) -{ - return TD (dyn_cast(source.decl)); -} - -template class DeclFromParser; -template class DeclFromUser; - -template class DeclFromParser : public TaggedASTDecl { -public: - DeclFromParser() : TaggedASTDecl() { } - DeclFromParser(D *_decl) : TaggedASTDecl(_decl) { } + while (0); - DeclFromUser GetOrigin(ClangASTImporter *importer); -}; - -template class DeclFromUser : public TaggedASTDecl { -public: - DeclFromUser() : TaggedASTDecl() { } - DeclFromUser(D *_decl) : TaggedASTDecl(_decl) { } - - DeclFromParser Import(ClangASTImporter *importer, ASTContext &dest_ctx); -}; - -template -DeclFromUser -DeclFromParser::GetOrigin(ClangASTImporter *importer) -{ - DeclFromUser <> origin_decl; - importer->ResolveDeclOrigin(this->decl, &origin_decl.decl, NULL); - if (origin_decl.IsInvalid()) - return DeclFromUser(); - return DeclFromUser(dyn_cast(origin_decl.decl)); -} - -template -DeclFromParser -DeclFromUser::Import(ClangASTImporter *importer, ASTContext &dest_ctx) -{ - DeclFromParser <> parser_generic_decl(importer->CopyDecl(&dest_ctx, &this->decl->getASTContext(), this->decl)); - if (parser_generic_decl.IsInvalid()) - return DeclFromParser(); - return DeclFromParser(dyn_cast(parser_generic_decl.decl)); + do + { + // Check the runtime only if the debug information didn't have a complete interface. + + lldb::ProcessSP process(m_target->GetProcessSP()); + + if (!process) + break; + + ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime()); + + TypeVendor *type_vendor = language_runtime->GetTypeVendor(); + + if (!type_vendor) + break; + + ConstString interface_name(interface_decl->getNameAsString().c_str()); + bool append = false; + uint32_t max_matches = 1; + std::vector types; + + if (!type_vendor->FindTypes(interface_name, + append, + max_matches, + types)) + break; + + const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr(); + + const ObjCInterfaceType *runtime_interface_type = dyn_cast(runtime_clang_type); + + if (!runtime_interface_type) + break; + + ObjCInterfaceDecl *runtime_interface_decl = runtime_interface_type->getDecl(); + + FindObjCMethodDeclsWithOrigin(current_id, + context, + runtime_interface_decl, + m_ast_context, + m_ast_importer, + "in runtime"); + } + while(0); } static bool @@ -1170,16 +1203,6 @@ ClangASTSource::FindObjCPropertyAndIvarDecls (NameSearchContext &context) SymbolContext null_sc; TypeList type_list; - lldb::ProcessSP process(m_target->GetProcessSP()); - - if (!process) - return; - - ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime()); - - if (!language_runtime) - return; - do { ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(const_cast(parser_iface_decl.decl)); @@ -1187,6 +1210,8 @@ ClangASTSource::FindObjCPropertyAndIvarDecls (NameSearchContext &context) if (!complete_interface_decl) break; + // We found the complete interface. The runtime never needs to be queried in this scenario. + DeclFromUser complete_iface_decl(complete_interface_decl); if (complete_iface_decl.decl == origin_iface_decl.decl) @@ -1198,18 +1223,29 @@ ClangASTSource::FindObjCPropertyAndIvarDecls (NameSearchContext &context) complete_iface_decl.decl, &complete_iface_decl->getASTContext()); - if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id, - context, - *m_ast_context, - m_ast_importer, - complete_iface_decl)) - return; + FindObjCPropertyAndIvarDeclsWithOrigin(current_id, + context, + *m_ast_context, + m_ast_importer, + complete_iface_decl); + + return; } while(0); do { - // Now check the runtime. + // Check the runtime only if the debug information didn't have a complete interface. + + lldb::ProcessSP process(m_target->GetProcessSP()); + + if (!process) + return; + + ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime()); + + if (!language_runtime) + return; TypeVendor *type_vendor = language_runtime->GetTypeVendor(); diff --git a/lldb/source/Target/ObjCLanguageRuntime.cpp b/lldb/source/Target/ObjCLanguageRuntime.cpp index d3c8a0c6f99d..0be1c96d1ce3 100644 --- a/lldb/source/Target/ObjCLanguageRuntime.cpp +++ b/lldb/source/Target/ObjCLanguageRuntime.cpp @@ -124,17 +124,6 @@ ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name) incomplete_type_sp = type_sp; } } - - // We didn't find any "real" definitions, so just use any??? Why was - // this being done? Prior to this, if there was 1 match only, then it - // would always use any objc definition, else we would only accept a - // definition if it was the real thing???? Doesn't make sense. - - if (incomplete_type_sp) - { - m_complete_class_cache[name] = incomplete_type_sp; - return incomplete_type_sp; - } } } return TypeSP();