forked from OSchip/llvm-project
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:
parent
58358897a3
commit
5540094ccd
|
@ -693,6 +693,63 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
|
||||||
} while(0);
|
} 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
|
static void
|
||||||
FindObjCMethodDeclsWithOrigin (unsigned int current_id,
|
FindObjCMethodDeclsWithOrigin (unsigned int current_id,
|
||||||
NameSearchContext &context,
|
NameSearchContext &context,
|
||||||
|
@ -807,7 +864,7 @@ ClangASTSource::FindObjCMethodDecls (NameSearchContext &context)
|
||||||
original_interface_decl,
|
original_interface_decl,
|
||||||
m_ast_context,
|
m_ast_context,
|
||||||
m_ast_importer,
|
m_ast_importer,
|
||||||
"in debug info");
|
"at origin");
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
StreamString ss;
|
StreamString ss;
|
||||||
|
@ -964,117 +1021,93 @@ ClangASTSource::FindObjCMethodDecls (NameSearchContext &context)
|
||||||
if (log)
|
if (log)
|
||||||
{
|
{
|
||||||
ASTDumper dumper((Decl*)copied_method_decl);
|
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);
|
context.AddNamedDecl(copied_method_decl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Try the debug information.
|
||||||
|
|
||||||
|
do
|
||||||
{
|
{
|
||||||
do
|
ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(const_cast<ObjCInterfaceDecl*>(interface_decl));
|
||||||
{
|
|
||||||
// We need to look at the runtime.
|
if (!complete_interface_decl)
|
||||||
|
break;
|
||||||
lldb::ProcessSP process(m_target->GetProcessSP());
|
|
||||||
|
// We found the complete interface. The runtime never needs to be queried in this scenario.
|
||||||
if (!process)
|
|
||||||
break;
|
DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl(complete_interface_decl);
|
||||||
|
|
||||||
ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
|
if (complete_interface_decl == interface_decl)
|
||||||
|
break; // already checked this one
|
||||||
TypeVendor *type_vendor = language_runtime->GetTypeVendor();
|
|
||||||
|
if (log)
|
||||||
if (!type_vendor)
|
log->Printf("CAS::FOPD[%d] trying origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
|
||||||
break;
|
current_id,
|
||||||
|
complete_interface_decl,
|
||||||
ConstString interface_name(interface_decl->getNameAsString().c_str());
|
&complete_iface_decl->getASTContext());
|
||||||
bool append = false;
|
|
||||||
uint32_t max_matches = 1;
|
FindObjCMethodDeclsWithOrigin(current_id,
|
||||||
std::vector <ClangASTType> types;
|
context,
|
||||||
|
complete_interface_decl,
|
||||||
if (!type_vendor->FindTypes(interface_name,
|
m_ast_context,
|
||||||
append,
|
m_ast_importer,
|
||||||
max_matches,
|
"in debug info");
|
||||||
types))
|
|
||||||
break;
|
return;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
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);
|
do
|
||||||
};
|
{
|
||||||
|
// Check the runtime only if the debug information didn't have a complete interface.
|
||||||
template <class D> class DeclFromUser : public TaggedASTDecl<D> {
|
|
||||||
public:
|
lldb::ProcessSP process(m_target->GetProcessSP());
|
||||||
DeclFromUser() : TaggedASTDecl<D>() { }
|
|
||||||
DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) { }
|
if (!process)
|
||||||
|
break;
|
||||||
DeclFromParser<D> Import(ClangASTImporter *importer, ASTContext &dest_ctx);
|
|
||||||
};
|
ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
|
||||||
|
|
||||||
template <class D>
|
TypeVendor *type_vendor = language_runtime->GetTypeVendor();
|
||||||
DeclFromUser<D>
|
|
||||||
DeclFromParser<D>::GetOrigin(ClangASTImporter *importer)
|
if (!type_vendor)
|
||||||
{
|
break;
|
||||||
DeclFromUser <> origin_decl;
|
|
||||||
importer->ResolveDeclOrigin(this->decl, &origin_decl.decl, NULL);
|
ConstString interface_name(interface_decl->getNameAsString().c_str());
|
||||||
if (origin_decl.IsInvalid())
|
bool append = false;
|
||||||
return DeclFromUser<D>();
|
uint32_t max_matches = 1;
|
||||||
return DeclFromUser<D>(dyn_cast<D>(origin_decl.decl));
|
std::vector <ClangASTType> types;
|
||||||
}
|
|
||||||
|
if (!type_vendor->FindTypes(interface_name,
|
||||||
template <class D>
|
append,
|
||||||
DeclFromParser<D>
|
max_matches,
|
||||||
DeclFromUser<D>::Import(ClangASTImporter *importer, ASTContext &dest_ctx)
|
types))
|
||||||
{
|
break;
|
||||||
DeclFromParser <> parser_generic_decl(importer->CopyDecl(&dest_ctx, &this->decl->getASTContext(), this->decl));
|
|
||||||
if (parser_generic_decl.IsInvalid())
|
const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr();
|
||||||
return DeclFromParser<D>();
|
|
||||||
return DeclFromParser<D>(dyn_cast<D>(parser_generic_decl.decl));
|
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
|
static bool
|
||||||
|
@ -1170,16 +1203,6 @@ ClangASTSource::FindObjCPropertyAndIvarDecls (NameSearchContext &context)
|
||||||
SymbolContext null_sc;
|
SymbolContext null_sc;
|
||||||
TypeList type_list;
|
TypeList type_list;
|
||||||
|
|
||||||
lldb::ProcessSP process(m_target->GetProcessSP());
|
|
||||||
|
|
||||||
if (!process)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
|
|
||||||
|
|
||||||
if (!language_runtime)
|
|
||||||
return;
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(const_cast<ObjCInterfaceDecl*>(parser_iface_decl.decl));
|
ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(const_cast<ObjCInterfaceDecl*>(parser_iface_decl.decl));
|
||||||
|
@ -1187,6 +1210,8 @@ ClangASTSource::FindObjCPropertyAndIvarDecls (NameSearchContext &context)
|
||||||
if (!complete_interface_decl)
|
if (!complete_interface_decl)
|
||||||
break;
|
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);
|
DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl(complete_interface_decl);
|
||||||
|
|
||||||
if (complete_iface_decl.decl == origin_iface_decl.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.decl,
|
||||||
&complete_iface_decl->getASTContext());
|
&complete_iface_decl->getASTContext());
|
||||||
|
|
||||||
if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
|
FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
|
||||||
context,
|
context,
|
||||||
*m_ast_context,
|
*m_ast_context,
|
||||||
m_ast_importer,
|
m_ast_importer,
|
||||||
complete_iface_decl))
|
complete_iface_decl);
|
||||||
return;
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
while(0);
|
while(0);
|
||||||
|
|
||||||
do
|
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();
|
TypeVendor *type_vendor = language_runtime->GetTypeVendor();
|
||||||
|
|
||||||
|
|
|
@ -124,17 +124,6 @@ ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name)
|
||||||
incomplete_type_sp = type_sp;
|
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();
|
return TypeSP();
|
||||||
|
|
Loading…
Reference in New Issue