diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -760,12 +760,32 @@ auto *pointer_type = llvm::dyn_cast(&type); assert(pointer_type); - SymbolFile *symbol_file = m_ast.GetSymbolFile(); + auto *symbol_file = static_cast(m_ast.GetSymbolFile()); if (!symbol_file) return nullptr; - Type *pointee_type = symbol_file->ResolveTypeUID( - pointer_type->getPointeeType()->getSymIndexId()); + auto pdb_pointee_type = pointer_type->getPointeeType()->getSymIndexId(); + if (symbol_file->IsObjCBuiltinTypeId(pdb_pointee_type)) { + // Clang emits id as objc_object* and we fill in the built-in "id" type + CompilerType id_type = m_ast.GetBasicType(eBasicTypeObjCID); + AddSourceInfoToDecl(type, decl); + return symbol_file->MakeType( + pointer_type->getSymIndexId(), ConstString("id"), + pointer_type->getLength(), nullptr, pdb_pointee_type, + lldb_private::Type::eEncodingIsUID, decl, id_type, + lldb_private::Type::ResolveState::Full); + } + if (symbol_file->IsObjCBuiltinTypeSel(pdb_pointee_type)) { + CompilerType id_type = m_ast.GetBasicType(eBasicTypeObjCSel); + AddSourceInfoToDecl(type, decl); + return symbol_file->MakeType( + pointer_type->getSymIndexId(), ConstString("SEL"), + pointer_type->getLength(), nullptr, pdb_pointee_type, + lldb_private::Type::eEncodingIsUID, decl, id_type, + lldb_private::Type::ResolveState::Full); + } + + Type *pointee_type = symbol_file->ResolveTypeUID(pdb_pointee_type); if (!pointee_type) return nullptr; diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -170,6 +170,8 @@ void DumpClangAST(lldb_private::Stream &s) override; bool IsaNSObjectOrNSProxy(const llvm::pdb::PDBSymbolTypeUDT &udt) const; + bool IsObjCBuiltinTypeId(lldb::user_id_t sym_uid) const; + bool IsObjCBuiltinTypeSel(lldb::user_id_t sym_uid) const; private: struct SecContribInfo { diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -2097,3 +2097,31 @@ auto *pdb_base_udt = llvm::dyn_cast(pdb_base_raw_up.get()); return IsaNSObjectOrNSProxy(*pdb_base_udt); } + +bool SymbolFilePDB::IsObjCBuiltinTypeId(user_id_t sym_uid) const { + std::unique_ptr pdb_sym_up = m_session_up->getSymbolById(sym_uid); + if (pdb_sym_up->getSymTag() != PDB_SymType::UDT) + return false; + + auto *pdb_sym_udt = llvm::dyn_cast(pdb_sym_up.get()); + if (pdb_sym_udt->getName() != "id" && + pdb_sym_udt->getName() != "objc_object") + return false; + + return true; +} + +bool SymbolFilePDB::IsObjCBuiltinTypeSel(user_id_t sym_uid) const { + std::unique_ptr pdb_sym_up = m_session_up->getSymbolById(sym_uid); + if (pdb_sym_up->getSymTag() != PDB_SymType::UDT) + return false; + + auto *pdb_sym_udt = llvm::dyn_cast(pdb_sym_up.get()); + if (pdb_sym_udt->getName() != "objc_selector") + return false; + + // TODO: ObjC selectors exist only for ObjC functions and they never occur + // freestanding. Thus, we know that all instances of this UDT are defined + // within ObjCInterfaceDecls. Can we add a check for that? + return true; +} diff --git a/lldb/test/Shell/Expr/objc-gnustep-print-pdb.m b/lldb/test/Shell/Expr/objc-gnustep-print-pdb.m deleted file mode 100644 --- a/lldb/test/Shell/Expr/objc-gnustep-print-pdb.m +++ /dev/null @@ -1,73 +0,0 @@ -// REQUIRES: objc-gnustep && system-windows -// -// RUN: %build %s --compiler=clang --objc-gnustep --output=%t - -#import "objc/runtime.h" - -@protocol NSCoding -@end - -#ifdef __has_attribute -#if __has_attribute(objc_root_class) -__attribute__((objc_root_class)) -#endif -#endif -@interface NSObject { - id isa; - int refcount; -} -@end -@implementation NSObject -- (id)class { - return object_getClass(self); -} -+ (id)new { - return class_createInstance(self, 0); -} -@end -@interface TestObj : NSObject { - int _int; - float _float; - char _char; - void *_ptr_void; - NSObject *_ptr_nsobject; - id _id_objc; -} -- (int)ok; -@end -@implementation TestObj -- (int)ok { - return self ? 0 : 1; -} -@end - -// RUN: %lldb -b -o "b objc-gnustep-print-pdb.m:72" -o "run" -o "p ptr" -o "p *ptr" -- %t | FileCheck %s -// -// CHECK: (lldb) b objc-gnustep-print-pdb.m:72 -// CHECK: Breakpoint {{.*}} at objc-gnustep-print-pdb.m:72 -// -// CHECK: (lldb) run -// CHECK: Process {{[0-9]+}} stopped -// CHECK: frame #0: {{.*}}`main at objc-gnustep-print-pdb.m:72 -// -// CHECK: (lldb) p ptr -// CHECK: (TestObj *) $0 = 0x{{[0-9]+}} -// -// CHECK: (lldb) p *ptr -// CHECK: (TestObj) $1 = { -// CHECK: NSObject = { -// CHECK: isa = 0x{{[0-9]+}} -// CHECK: refcount -// CHECK: } -// CHECK: _int = 0 -// CHECK: _float = 0 -// CHECK: _char = '\0' -// CHECK: _ptr_void = 0x{{0+}} -// CHECK: _ptr_nsobject = nil -// CHECK: _id_objc = nil -// CHECK: } - -int main() { - TestObj *ptr = [TestObj new]; - return [ptr ok]; -} diff --git a/lldb/test/Shell/Expr/objc-gnustep-print.m b/lldb/test/Shell/Expr/objc-gnustep-print.m --- a/lldb/test/Shell/Expr/objc-gnustep-print.m +++ b/lldb/test/Shell/Expr/objc-gnustep-print.m @@ -1,5 +1,4 @@ // REQUIRES: objc-gnustep -// XFAIL: system-windows // // RUN: %build %s --compiler=clang --objc-gnustep --output=%t