Index: lldb/packages/Python/lldbsuite/test/lang/objc/modules-app-update/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/lang/objc/modules-app-update/Makefile @@ -0,0 +1,5 @@ +CFLAGS_EXTRAS = -I$(BUILDDIR) +USE_PRIVATE_MODULE_CACHE := YES +OBJC_SOURCES := main.m foo.m + +include Makefile.rules Index: lldb/packages/Python/lldbsuite/test/lang/objc/modules-app-update/TestClangModulesAppUpdate.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/lang/objc/modules-app-update/TestClangModulesAppUpdate.py @@ -0,0 +1,61 @@ +from __future__ import print_function + +import unittest2 +import os +import shutil + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestClangModuleAppUpdate(TestBase): + mydir = TestBase.compute_mydir(__file__) + + def setUp(self): + TestBase.setUp(self) + + @skipUnlessDarwin + @skipIf(debug_info=no_match(["gmodules"])) + def test_rebuild_app_modules_untouched(self): + with open(self.getBuildArtifact("module.modulemap"), "w") as f: + f.write(""" + module Foo { header "f.h" } + """) + with open(self.getBuildArtifact("f.h"), "w") as f: + f.write(""" + @import Foundation; + @interface Foo : NSObject { + int i; + } + +(instancetype)init; + @end + """) + + mod_cache = self.getBuildArtifact("private-module-cache") + import os + if os.path.isdir(mod_cache): + shutil.rmtree(mod_cache) + self.build() + self.assertTrue(os.path.isdir(mod_cache), "module cache exists") + + target, process, _, bkpt = lldbutil.run_to_source_breakpoint( + self, "break here", lldb.SBFileSpec("main.m")) + bar = target.FindTypes('Bar').GetTypeAtIndex(0) + foo = bar.GetDirectBaseClassAtIndex(0).GetType() + self.assertEqual(foo.GetNumberOfFields(), 1) + self.assertEqual(foo.GetFieldAtIndex(0).GetName(), "i") + + # Rebuild. + process.Kill() + os.remove(self.getBuildArtifact('main.o')) + os.remove(self.getBuildArtifact('a.out')) + self.build() + + # Reattach. + target, process, _, _ = lldbutil.run_to_breakpoint_do_run(self, target, bkpt) + bar = target.FindTypes('Bar').GetTypeAtIndex(0) + foo = bar.GetDirectBaseClassAtIndex(0).GetType() + self.assertEqual(foo.GetNumberOfFields(), 1) + self.assertEqual(foo.GetFieldAtIndex(0).GetName(), "i") Index: lldb/packages/Python/lldbsuite/test/lang/objc/modules-app-update/foo.m =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/lang/objc/modules-app-update/foo.m @@ -0,0 +1,7 @@ +@import Foundation; +@import Foo; +@implementation Foo ++(instancetype)init { + return [super init]; +} +@end Index: lldb/packages/Python/lldbsuite/test/lang/objc/modules-app-update/main.m =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/lang/objc/modules-app-update/main.m @@ -0,0 +1,17 @@ +@import Umbrella; + +@interface Bar : Foo ++(instancetype)init; +@end + +@implementation Bar ++(instancetype)init { + return [super init]; +} +@end + +int main(int argc, char **argv) { + id bar = [Bar new]; + [bar i]; // break here + return 0; +} Index: lldb/packages/Python/lldbsuite/test/lang/objc/modules-app-update/module.modulemap =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/lang/objc/modules-app-update/module.modulemap @@ -0,0 +1,4 @@ +module Umbrella { + header "umbrella.h" + export * +} Index: lldb/packages/Python/lldbsuite/test/lang/objc/modules-app-update/umbrella.h =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/lang/objc/modules-app-update/umbrella.h @@ -0,0 +1 @@ +@import Foo; Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -187,7 +187,7 @@ languages.Insert(die.GetCU()->GetLanguageType()); llvm::DenseSet searched_symbol_files; clang_module_sp->GetSymbolFile()->FindTypes(decl_context, languages, - searched_symbol_files, pcm_types); + searched_symbol_files, pcm_types); if (pcm_types.Empty()) { // Since this type is defined in one of the Clang modules imported // by this symbol file, search all of them. Instead of calling @@ -222,6 +222,19 @@ if (!type) return TypeSP(); + // Under normal operation pcm_type is a shallow forward declaration + // that gets completed later. This is necessary to support cyclic + // data structures. If, however, pcm_type is already complete (for + // example, because it was loaded for a different target before), + // the definition needs to be imported right away, too. + // Type::ResolveClangType() effectively ignores the ResolveState + // inside type_sp and only looks at IsDefined(), so it never calls + // ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo(), + // which does extra work for Objective-C classes. This would result + // in only the forward declaration to be visible. + if (pcm_type.IsDefined()) + GetClangASTImporter().RequireCompleteType(ClangUtil::GetQualType(type)); + SymbolFileDWARF *dwarf = die.GetDWARF(); TypeSP type_sp(new Type( die.GetID(), dwarf, pcm_type_sp->GetName(), pcm_type_sp->GetByteSize(),