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.

<rdar://problem/12608895>

llvm-svn: 167299
This commit is contained in:
Sean Callanan 2012-11-02 17:09:58 +00:00
parent 58358897a3
commit 5540094ccd
2 changed files with 156 additions and 131 deletions

View File

@ -693,6 +693,63 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
} while(0);
}
template <class D> 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 D2, template <class D> class TD, class D1>
TD<D2>
DynCast(TD<D1> source)
{
return TD<D2> (dyn_cast<D2>(source.decl));
}
template <class D = Decl> class DeclFromParser;
template <class D = Decl> class DeclFromUser;
template <class D> class DeclFromParser : public TaggedASTDecl<D> {
public:
DeclFromParser() : TaggedASTDecl<D>() { }
DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) { }
DeclFromUser<D> GetOrigin(ClangASTImporter *importer);
};
template <class D> class DeclFromUser : public TaggedASTDecl<D> {
public:
DeclFromUser() : TaggedASTDecl<D>() { }
DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) { }
DeclFromParser<D> Import(ClangASTImporter *importer, ASTContext &dest_ctx);
};
template <class D>
DeclFromUser<D>
DeclFromParser<D>::GetOrigin(ClangASTImporter *importer)
{
DeclFromUser <> origin_decl;
importer->ResolveDeclOrigin(this->decl, &origin_decl.decl, NULL);
if (origin_decl.IsInvalid())
return DeclFromUser<D>();
return DeclFromUser<D>(dyn_cast<D>(origin_decl.decl));
}
template <class D>
DeclFromParser<D>
DeclFromUser<D>::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<D>();
return DeclFromParser<D>(dyn_cast<D>(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.
ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(const_cast<ObjCInterfaceDecl*>(interface_decl));
lldb::ProcessSP process(m_target->GetProcessSP());
if (!complete_interface_decl)
break;
if (!process)
break;
// We found the complete interface. The runtime never needs to be queried in this scenario.
ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl(complete_interface_decl);
TypeVendor *type_vendor = language_runtime->GetTypeVendor();
if (complete_interface_decl == interface_decl)
break; // already checked this one
if (!type_vendor)
break;
if (log)
log->Printf("CAS::FOPD[%d] trying origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
current_id,
complete_interface_decl,
&complete_iface_decl->getASTContext());
ConstString interface_name(interface_decl->getNameAsString().c_str());
bool append = false;
uint32_t max_matches = 1;
std::vector <ClangASTType> types;
FindObjCMethodDeclsWithOrigin(current_id,
context,
complete_interface_decl,
m_ast_context,
m_ast_importer,
"in debug info");
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<ObjCInterfaceType>(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);
return;
}
}
while (0);
template <class D> 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;
};
do
{
// Check the runtime only if the debug information didn't have a complete interface.
template <class D2, template <class D> class TD, class D1>
TD<D2>
DynCast(TD<D1> source)
{
return TD<D2> (dyn_cast<D2>(source.decl));
}
lldb::ProcessSP process(m_target->GetProcessSP());
template <class D = Decl> class DeclFromParser;
template <class D = Decl> class DeclFromUser;
if (!process)
break;
template <class D> class DeclFromParser : public TaggedASTDecl<D> {
public:
DeclFromParser() : TaggedASTDecl<D>() { }
DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) { }
ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
DeclFromUser<D> GetOrigin(ClangASTImporter *importer);
};
TypeVendor *type_vendor = language_runtime->GetTypeVendor();
template <class D> class DeclFromUser : public TaggedASTDecl<D> {
public:
DeclFromUser() : TaggedASTDecl<D>() { }
DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) { }
if (!type_vendor)
break;
DeclFromParser<D> Import(ClangASTImporter *importer, ASTContext &dest_ctx);
};
ConstString interface_name(interface_decl->getNameAsString().c_str());
bool append = false;
uint32_t max_matches = 1;
std::vector <ClangASTType> types;
template <class D>
DeclFromUser<D>
DeclFromParser<D>::GetOrigin(ClangASTImporter *importer)
{
DeclFromUser <> origin_decl;
importer->ResolveDeclOrigin(this->decl, &origin_decl.decl, NULL);
if (origin_decl.IsInvalid())
return DeclFromUser<D>();
return DeclFromUser<D>(dyn_cast<D>(origin_decl.decl));
}
if (!type_vendor->FindTypes(interface_name,
append,
max_matches,
types))
break;
template <class D>
DeclFromParser<D>
DeclFromUser<D>::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<D>();
return DeclFromParser<D>(dyn_cast<D>(parser_generic_decl.decl));
const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr();
const ObjCInterfaceType *runtime_interface_type = dyn_cast<ObjCInterfaceType>(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<ObjCInterfaceDecl*>(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<const ObjCInterfaceDecl> 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();

View File

@ -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();