From f0c5aeb69011197d1ef1bbed7ba363d52e95c5d8 Mon Sep 17 00:00:00 2001 From: Sean Callanan Date: Mon, 20 Apr 2015 16:31:29 +0000 Subject: [PATCH] This patch implements several improvements to the module-loading support for the expression parser. - It adds support for auto-loading modules referred to by a compile unit. These references are currently in the form of empty translation units. This functionality is gated by the setting target.auto-import-clang-modules (boolean) = false - It improves and corrects support for loading macros from modules, currently by textually pasting all #defines into the user's expression. The improvements center around including only those modules that are relevant to the current context - hand-loaded modules and the modules that are imported from the current compile unit. - It adds an "opt-in" mechanism for all of this functionality. Modules have to be explicitly imported (via @import) or auto-loaded (by enabling the above setting) to enable any of this functionality. It also adds support to the compile unit and symbol file code to deal with empty translation units that indicate module imports, and plumbs this through to the CompileUnit interface. Finally, it makes the following changes to the test suite: - It adds a testcase that verifies that modules are automatically loaded when the appropriate setting is enabled (lang/objc/modules-auto-import); and - It modifies lanb/objc/modules-incomplete to test the case where a module #undefs something that is #defined in another module. llvm-svn: 235313 --- .../lldb/Expression/ClangModulesDeclVendor.h | 72 +++++- .../lldb/Expression/ClangPersistentVariables.h | 16 ++ lldb/include/lldb/Symbol/CompileUnit.h | 25 ++- lldb/include/lldb/Symbol/SymbolFile.h | 1 + lldb/include/lldb/Symbol/SymbolVendor.h | 4 + lldb/include/lldb/Target/Target.h | 3 + lldb/source/Expression/ClangExpressionParser.cpp | 37 ++-- lldb/source/Expression/ClangModulesDeclVendor.cpp | 245 ++++++++++++++++++++- lldb/source/Expression/ClangUserExpression.cpp | 30 ++- .../Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp | 25 +++ .../Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 79 ++++++- .../Plugins/SymbolFile/DWARF/SymbolFileDWARF.h | 15 +- .../SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp | 25 ++- .../SymbolFile/DWARF/SymbolFileDWARFDebugMap.h | 1 + .../Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp | 6 + .../Plugins/SymbolFile/Symtab/SymbolFileSymtab.h | 3 + lldb/source/Symbol/CompileUnit.cpp | 17 ++ lldb/source/Symbol/SymbolVendor.cpp | 15 ++ lldb/source/Target/Target.cpp | 9 + .../data-formatter/typedef_array/Makefile | 4 - lldb/test/lang/objc/modules-auto-import/Makefile | 6 + .../modules-auto-import/TestModulesAutoImport.py | 78 +++++++ lldb/test/lang/objc/modules-auto-import/main.m | 7 + .../modules-incomplete/TestIncompleteModules.py | 6 + lldb/test/lang/objc/modules-incomplete/myModule.h | 2 + 25 files changed, 676 insertions(+), 55 deletions(-) create mode 100644 lldb/test/lang/objc/modules-auto-import/Makefile create mode 100644 lldb/test/lang/objc/modules-auto-import/TestModulesAutoImport.py create mode 100644 lldb/test/lang/objc/modules-auto-import/main.m diff --git a/lldb/include/lldb/Expression/ClangModulesDeclVendor.h b/lldb/include/lldb/Expression/ClangModulesDeclVendor.h index 5bc383d..a8297c8 100644 --- a/lldb/include/lldb/Expression/ClangModulesDeclVendor.h +++ b/lldb/include/lldb/Expression/ClangModulesDeclVendor.h @@ -15,6 +15,7 @@ #include "lldb/Symbol/DeclVendor.h" #include "lldb/Target/Platform.h" +#include #include namespace lldb_private @@ -34,6 +35,10 @@ public: static ClangModulesDeclVendor * Create(Target &target); + typedef std::vector ModulePath; + typedef uintptr_t ModuleID; + typedef std::vector ModuleVector; + //------------------------------------------------------------------ /// Add a module to the list of modules to search. /// @@ -41,6 +46,10 @@ public: /// The path to the exact module to be loaded. E.g., if the desired /// module is std.io, then this should be { "std", "io" }. /// + /// @param[in] exported_modules + /// If non-NULL, a pointer to a vector to populate with the ID of every + /// module that is re-exported by the specified module. + /// /// @param[in] error_stream /// A stream to populate with the output of the Clang parser when /// it tries to load the module. @@ -51,18 +60,69 @@ public: /// load, then this will always return false for this ModuleImporter. //------------------------------------------------------------------ virtual bool - AddModule(std::vector &path, Stream &error_stream) = 0; + AddModule(ModulePath &path, + ModuleVector *exported_modules, + Stream &error_stream) = 0; //------------------------------------------------------------------ - /// Enumerate all the macros that are currently visible. + /// Add all modules referred to in a given compilation unit to the list + /// of modules to search. + /// + /// @param[in] cu + /// The compilation unit to scan for imported modules. + /// + /// @param[in] exported_modules + /// A vector to populate with the ID of each module loaded (directly + /// and via re-exports) in this way. + /// + /// @param[in] error_stream + /// A stream to populate with the output of the Clang parser when + /// it tries to load the modules. + /// + /// @return + /// True if all modules referred to by the compilation unit could be + /// loaded; false if one could not be loaded. If the compiler + /// encountered a fatal error during a previous module + /// load, then this will always return false for this ModuleImporter. + //------------------------------------------------------------------ + virtual bool + AddModulesForCompileUnit(CompileUnit &cu, + ModuleVector &exported_modules, + Stream &error_stream) = 0; + + //------------------------------------------------------------------ + /// Enumerate all the macros that are defined by a given set of modules + /// that are already imported. + /// + /// @param[in] modules + /// The unique IDs for all modules to query. Later modules have higher + /// priority, just as if you @imported them in that order. This matters + /// if module A #defines a macro and module B #undefs it. /// /// @param[in] handler - /// A function that receives the text of each #define macro. - /// If handler returns true, this function returns immediately, - /// without calling handler again. + /// A function to call with the text of each #define (including the + /// #define directive). #undef directives are not included; we simply + /// elide any corresponding #define. If this function returns true, + /// we stop the iteration immediately. //------------------------------------------------------------------ virtual void - ForEachMacro(std::function handler) = 0; + ForEachMacro(const ModuleVector &modules, + std::function handler) = 0; + + //------------------------------------------------------------------ + /// Query whether Clang supports modules for a particular language. + /// LLDB uses this to decide whether to try to find the modules loaded + /// by a gaiven compile unit. + /// + /// @param[in] language + /// The language to query for. + /// + /// @return + /// True if Clang has modules for the given language. + //------------------------------------------------------------------ + static bool + LanguageSupportsClangModules (lldb::LanguageType language); + }; } diff --git a/lldb/include/lldb/Expression/ClangPersistentVariables.h b/lldb/include/lldb/Expression/ClangPersistentVariables.h index 6d9dae9..247f87f 100644 --- a/lldb/include/lldb/Expression/ClangPersistentVariables.h +++ b/lldb/include/lldb/Expression/ClangPersistentVariables.h @@ -11,6 +11,8 @@ #define liblldb_ClangPersistentVariables_h_ #include "lldb/Expression/ClangExpressionVariable.h" +#include "lldb/Expression/ClangModulesDeclVendor.h" + #include "llvm/ADT/DenseMap.h" namespace lldb_private @@ -63,11 +65,25 @@ public: clang::TypeDecl * GetPersistentType (const ConstString &name); + void + AddHandLoadedClangModule(ClangModulesDeclVendor::ModuleID module) + { + m_hand_loaded_clang_modules.push_back(module); + } + + const ClangModulesDeclVendor::ModuleVector &GetHandLoadedClangModules() + { + return m_hand_loaded_clang_modules; + } + private: uint32_t m_next_persistent_variable_id; ///< The counter used by GetNextResultName(). typedef llvm::DenseMap PersistentTypeMap; PersistentTypeMap m_persistent_types; ///< The persistent types declared by the user. + + ClangModulesDeclVendor::ModuleVector m_hand_loaded_clang_modules; ///< These are Clang modules we hand-loaded; these are the highest- + ///< priority source for macros. }; } diff --git a/lldb/include/lldb/Symbol/CompileUnit.h b/lldb/include/lldb/Symbol/CompileUnit.h index f9238eb..e0c0693 100644 --- a/lldb/include/lldb/Symbol/CompileUnit.h +++ b/lldb/include/lldb/Symbol/CompileUnit.h @@ -256,6 +256,18 @@ public: //------------------------------------------------------------------ FileSpecList& GetSupportFiles (); + + //------------------------------------------------------------------ + /// Get the compile unit's imported module list. + /// + /// This reports all the imports that the compile unit made, + /// including the current module. + /// + /// @return + /// A list of imported module names. + //------------------------------------------------------------------ + const std::vector & + GetImportedModules (); //------------------------------------------------------------------ /// Get the SymbolFile plug-in user data. @@ -400,6 +412,8 @@ protected: Flags m_flags; ///< Compile unit flags that help with partial parsing. std::vector m_functions; ///< The sparsely populated list of shared pointers to functions ///< that gets populated as functions get partially parsed. + std::vector m_imported_modules; ///< All modules, including the current module, imported by this + ///< compile unit. FileSpecList m_support_files; ///< Files associated with this compile unit's line table and declarations. std::unique_ptr m_line_table_ap; ///< Line table that will get parsed on demand. lldb::VariableListSP m_variables; ///< Global and static variable list that will get parsed on demand. @@ -407,11 +421,12 @@ protected: private: enum { - flagsParsedAllFunctions = (1u << 0), ///< Have we already parsed all our functions - flagsParsedVariables = (1u << 1), ///< Have we already parsed globals and statics? - flagsParsedSupportFiles = (1u << 2), ///< Have we already parsed the support files for this compile unit? - flagsParsedLineTable = (1u << 3), ///< Have we parsed the line table already? - flagsParsedLanguage = (1u << 4) ///< Have we parsed the line table already? + flagsParsedAllFunctions = (1u << 0), ///< Have we already parsed all our functions + flagsParsedVariables = (1u << 1), ///< Have we already parsed globals and statics? + flagsParsedSupportFiles = (1u << 2), ///< Have we already parsed the support files for this compile unit? + flagsParsedLineTable = (1u << 3), ///< Have we parsed the line table already? + flagsParsedLanguage = (1u << 4), ///< Have we parsed the line table already? + flagsParsedImportedModules = (1u << 5) ///< Have we parsed the imported modules already? }; DISALLOW_COPY_AND_ASSIGN (CompileUnit); diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index 6df3d49..0efe034 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -124,6 +124,7 @@ public: virtual size_t ParseCompileUnitFunctions (const SymbolContext& sc) = 0; virtual bool ParseCompileUnitLineTable (const SymbolContext& sc) = 0; virtual bool ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files) = 0; + virtual bool ParseImportedModules (const SymbolContext &sc, std::vector &imported_modules) = 0; virtual size_t ParseFunctionBlocks (const SymbolContext& sc) = 0; virtual size_t ParseTypes (const SymbolContext& sc) = 0; virtual size_t ParseVariablesForContext (const SymbolContext& sc) = 0; diff --git a/lldb/include/lldb/Symbol/SymbolVendor.h b/lldb/include/lldb/Symbol/SymbolVendor.h index cddf216..248918a 100644 --- a/lldb/include/lldb/Symbol/SymbolVendor.h +++ b/lldb/include/lldb/Symbol/SymbolVendor.h @@ -66,6 +66,10 @@ public: virtual bool ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files); + + virtual bool + ParseImportedModules (const SymbolContext &sc, + std::vector &imported_modules); virtual size_t ParseFunctionBlocks (const SymbolContext& sc); diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 4303864..872a8ec 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -128,6 +128,9 @@ public: GetClangModuleSearchPaths (); bool + GetEnableAutoImportClangModules () const; + + bool GetEnableSyntheticValue () const; uint32_t diff --git a/lldb/source/Expression/ClangExpressionParser.cpp b/lldb/source/Expression/ClangExpressionParser.cpp index c7d84e6..57e620b 100644 --- a/lldb/source/Expression/ClangExpressionParser.cpp +++ b/lldb/source/Expression/ClangExpressionParser.cpp @@ -24,6 +24,7 @@ #include "lldb/Expression/ClangExpression.h" #include "lldb/Expression/ClangExpressionDeclMap.h" #include "lldb/Expression/ClangModulesDeclVendor.h" +#include "lldb/Expression/ClangPersistentVariables.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/IRDynamicChecks.h" #include "lldb/Expression/IRInterpreter.h" @@ -96,12 +97,15 @@ std::string GetBuiltinIncludePath(const char *Argv0) { class ClangExpressionParser::LLDBPreprocessorCallbacks : public PPCallbacks { - ClangModulesDeclVendor &m_decl_vendor; - StreamString m_error_stream; - bool m_has_errors = false; + ClangModulesDeclVendor &m_decl_vendor; + ClangPersistentVariables &m_persistent_vars; + StreamString m_error_stream; + bool m_has_errors = false; public: - LLDBPreprocessorCallbacks(ClangModulesDeclVendor &decl_vendor) : - m_decl_vendor(decl_vendor) + LLDBPreprocessorCallbacks(ClangModulesDeclVendor &decl_vendor, + ClangPersistentVariables &persistent_vars) : + m_decl_vendor(decl_vendor), + m_persistent_vars(persistent_vars) { } @@ -109,19 +113,26 @@ public: ModuleIdPath path, const clang::Module * /*null*/) { - std::vector string_path; + std::vector string_path; for (const std::pair &component : path) { - string_path.push_back(component.first->getName()); + string_path.push_back(ConstString(component.first->getName())); } StreamString error_stream; - if (!m_decl_vendor.AddModule(string_path, m_error_stream)) + ClangModulesDeclVendor::ModuleVector exported_modules; + + if (!m_decl_vendor.AddModule(string_path, &exported_modules, m_error_stream)) { m_has_errors = true; } + + for (ClangModulesDeclVendor::ModuleID module : exported_modules) + { + m_persistent_vars.AddHandLoadedClangModule(module); + } } bool hasErrors() @@ -298,7 +309,7 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, if (ClangModulesDeclVendor *decl_vendor = target_sp->GetClangModulesDeclVendor()) { - std::unique_ptr pp_callbacks(new LLDBPreprocessorCallbacks(*decl_vendor)); + std::unique_ptr pp_callbacks(new LLDBPreprocessorCallbacks(*decl_vendor, target_sp->GetPersistentVariables())); m_pp_callbacks = static_cast(pp_callbacks.get()); m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks)); } @@ -309,10 +320,10 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, m_builtin_context.reset(new Builtin::Context()); std::unique_ptr ast_context(new ASTContext(m_compiler->getLangOpts(), - m_compiler->getSourceManager(), - m_compiler->getPreprocessor().getIdentifierTable(), - *m_selector_table.get(), - *m_builtin_context.get())); + m_compiler->getSourceManager(), + m_compiler->getPreprocessor().getIdentifierTable(), + *m_selector_table.get(), + *m_builtin_context.get())); ast_context->InitBuiltinTypes(m_compiler->getTarget()); diff --git a/lldb/source/Expression/ClangModulesDeclVendor.cpp b/lldb/source/Expression/ClangModulesDeclVendor.cpp index efa50b1..b4dd73b 100644 --- a/lldb/source/Expression/ClangModulesDeclVendor.cpp +++ b/lldb/source/Expression/ClangModulesDeclVendor.cpp @@ -16,6 +16,7 @@ #include "lldb/Host/FileSpec.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/CompileUnit.h" #include "lldb/Target/Target.h" #include "clang/Basic/TargetInfo.h" @@ -61,9 +62,15 @@ namespace { std::unique_ptr &&parser); virtual bool - AddModule(std::vector &path, + AddModule(ModulePath &path, + ModuleVector *exported_modules, Stream &error_stream) override; + virtual bool + AddModulesForCompileUnit(CompileUnit &cu, + ModuleVector &exported_modules, + Stream &error_stream) override; + virtual uint32_t FindDecls (const ConstString &name, bool append, @@ -71,19 +78,36 @@ namespace { std::vector &decls) override; virtual void - ForEachMacro(std::function handler) override; + ForEachMacro(const ModuleVector &modules, + std::function handler) override; ~ClangModulesDeclVendorImpl(); private: + void + ReportModuleExportsHelper (std::set &exports, + clang::Module *module); + + void + ReportModuleExports (ModuleVector &exports, + clang::Module *module); + clang::ModuleLoadResult DoGetModule(clang::ModuleIdPath path, bool make_visible); + bool m_enabled = false; + llvm::IntrusiveRefCntPtr m_diagnostics_engine; llvm::IntrusiveRefCntPtr m_compiler_invocation; std::unique_ptr m_compiler_instance; std::unique_ptr m_parser; size_t m_source_location_index = 0; // used to give name components fake SourceLocations + + typedef std::vector ImportedModule; + typedef std::map ImportedModuleMap; + typedef std::set ImportedModuleSet; + ImportedModuleMap m_imported_modules; + ImportedModuleSet m_user_imported_modules; }; } @@ -156,12 +180,47 @@ ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl(llvm::IntrusiveRefCntPtr< m_diagnostics_engine(diagnostics_engine), m_compiler_invocation(compiler_invocation), m_compiler_instance(std::move(compiler_instance)), - m_parser(std::move(parser)) + m_parser(std::move(parser)), + m_imported_modules() { } +void +ClangModulesDeclVendorImpl::ReportModuleExportsHelper (std::set &exports, + clang::Module *module) +{ + if (exports.count(reinterpret_cast(module))) + return; + + exports.insert(reinterpret_cast(module)); + + llvm::SmallVector sub_exports; + + module->getExportedModules(sub_exports); + + for (clang::Module *module : sub_exports) + { + ReportModuleExportsHelper(exports, module); + } +} + +void +ClangModulesDeclVendorImpl::ReportModuleExports (ClangModulesDeclVendor::ModuleVector &exports, + clang::Module *module) +{ + std::set exports_set; + + ReportModuleExportsHelper(exports_set, module); + + for (ModuleID module : exports_set) + { + exports.push_back(module); + } +} + bool -ClangModulesDeclVendorImpl::AddModule(std::vector &path, +ClangModulesDeclVendorImpl::AddModule(ModulePath &path, + ModuleVector *exported_modules, Stream &error_stream) { // Fail early. @@ -172,9 +231,31 @@ ClangModulesDeclVendorImpl::AddModule(std::vector &path, return false; } - if (!m_compiler_instance->getPreprocessor().getHeaderSearchInfo().lookupModule(path[0])) + // Check if we've already imported this module. + + std::vector imported_module; + + for (ConstString path_component : path) { - error_stream.Printf("error: Header search couldn't locate module %s\n", path[0].str().c_str()); + imported_module.push_back(path_component); + } + + { + ImportedModuleMap::iterator mi = m_imported_modules.find(imported_module); + + if (mi != m_imported_modules.end()) + { + if (exported_modules) + { + ReportModuleExports(*exported_modules, mi->second); + } + return true; + } + } + + if (!m_compiler_instance->getPreprocessor().getHeaderSearchInfo().lookupModule(path[0].GetStringRef())) + { + error_stream.Printf("error: Header search couldn't locate module %s\n", path[0].AsCString()); return false; } @@ -183,9 +264,9 @@ ClangModulesDeclVendorImpl::AddModule(std::vector &path, { clang::SourceManager &source_manager = m_compiler_instance->getASTContext().getSourceManager(); - for (llvm::StringRef &component : path) + for (ConstString path_component : path) { - clang_path.push_back(std::make_pair(&m_compiler_instance->getASTContext().Idents.get(component), + clang_path.push_back(std::make_pair(&m_compiler_instance->getASTContext().Idents.get(path_component.GetStringRef()), source_manager.getLocForStartOfFile(source_manager.getMainFileID()).getLocWithOffset(m_source_location_index++))); } } @@ -199,7 +280,7 @@ ClangModulesDeclVendorImpl::AddModule(std::vector &path, if (!top_level_module) { diagnostic_consumer->DumpDiagnostics(error_stream); - error_stream.Printf("error: Couldn't load top-level module %s\n", path[0].str().c_str()); + error_stream.Printf("error: Couldn't load top-level module %s\n", path[0].AsCString()); return false; } @@ -207,7 +288,7 @@ ClangModulesDeclVendorImpl::AddModule(std::vector &path, for (size_t ci = 1; ci < path.size(); ++ci) { - llvm::StringRef &component = path[ci]; + llvm::StringRef component = path[ci].GetStringRef(); submodule = submodule->findSubmodule(component.str()); if (!submodule) { @@ -219,7 +300,66 @@ ClangModulesDeclVendorImpl::AddModule(std::vector &path, clang::Module *requested_module = DoGetModule(clang_path, true); - return (requested_module != nullptr); + if (requested_module != nullptr) + { + if (exported_modules) + { + ReportModuleExports(*exported_modules, requested_module); + } + + m_imported_modules[imported_module] = requested_module; + + m_enabled = true; + + return true; + } + + return false; +} + + +bool +ClangModulesDeclVendor::LanguageSupportsClangModules (lldb::LanguageType language) +{ + switch (language) + { + default: + return false; + // C++ and friends to be added + case lldb::LanguageType::eLanguageTypeC: + case lldb::LanguageType::eLanguageTypeC11: + case lldb::LanguageType::eLanguageTypeC89: + case lldb::LanguageType::eLanguageTypeC99: + case lldb::LanguageType::eLanguageTypeObjC: + return true; + } +} + +bool +ClangModulesDeclVendorImpl::AddModulesForCompileUnit(CompileUnit &cu, + ClangModulesDeclVendor::ModuleVector &exported_modules, + Stream &error_stream) +{ + if (LanguageSupportsClangModules(cu.GetLanguage())) + { + std::vector imported_modules = cu.GetImportedModules(); + + for (ConstString imported_module : imported_modules) + { + std::vector path; + + path.push_back(imported_module); + + if (!AddModule(path, &exported_modules, error_stream)) + { + return false; + } + } + + return true; + } + + return true; } // ClangImporter::lookupValue @@ -230,6 +370,11 @@ ClangModulesDeclVendorImpl::FindDecls (const ConstString &name, uint32_t max_matches, std::vector &decls) { + if (!m_enabled) + { + return 0; + } + if (!append) decls.clear(); @@ -257,14 +402,90 @@ ClangModulesDeclVendorImpl::FindDecls (const ConstString &name, } void -ClangModulesDeclVendorImpl::ForEachMacro(std::function handler) +ClangModulesDeclVendorImpl::ForEachMacro(const ClangModulesDeclVendor::ModuleVector &modules, + std::function handler) { + if (!m_enabled) + { + return; + } + + typedef std::map ModulePriorityMap; + ModulePriorityMap module_priorities; + + ssize_t priority = 0; + + for (ModuleID module : modules) + { + module_priorities[module] = priority++; + } + + if (m_compiler_instance->getPreprocessor().getExternalSource()) + { + m_compiler_instance->getPreprocessor().getExternalSource()->ReadDefinedMacros(); + } for (clang::Preprocessor::macro_iterator mi = m_compiler_instance->getPreprocessor().macro_begin(), me = m_compiler_instance->getPreprocessor().macro_end(); mi != me; ++mi) { + const clang::IdentifierInfo *ii = nullptr; + + { + if (clang::IdentifierInfoLookup *lookup = m_compiler_instance->getPreprocessor().getIdentifierTable().getExternalIdentifierLookup()) + { + lookup->get(mi->first->getName()); + } + if (!ii) + { + ii = mi->first; + } + } + + ssize_t found_priority = -1; + clang::MacroInfo *info = nullptr; + + for (clang::MacroDirective *directive = m_compiler_instance->getPreprocessor().getMacroDirectiveHistory(ii); + directive != nullptr; + directive = directive->getPrevious()) + { + unsigned module_id = directive->getOwningModuleID(); + + if (!module_id) + continue; + + clang::Module *module = m_compiler_instance->getModuleManager()->getModule(module_id); + + { + ModulePriorityMap::iterator pi = module_priorities.find(reinterpret_cast(module)); + + if (pi != module_priorities.end() && pi->second > found_priority) + { + info = directive->getMacroInfo(); + found_priority = pi->second; + } + } + + clang::Module *top_level_module = module->getTopLevelModule(); + + if (top_level_module != module) + { + ModulePriorityMap::iterator pi = module_priorities.find(reinterpret_cast(top_level_module)); + + if ((pi != module_priorities.end()) && pi->second > found_priority) + { + info = directive->getMacroInfo(); + found_priority = pi->second; + } + } + } + + if (!info) + { + continue; + } + if (mi->second->getKind() == clang::MacroDirective::MD_Define) { std::string macro_expansion = "#define "; diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index 08ee437..ba28431 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -458,7 +458,35 @@ ClangUserExpression::Parse (Stream &error_stream, if (ClangModulesDeclVendor *decl_vendor = m_target->GetClangModulesDeclVendor()) { - decl_vendor->ForEachMacro([log, &prefix] (const std::string &expansion) -> bool { + const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = m_target->GetPersistentVariables().GetHandLoadedClangModules(); + ClangModulesDeclVendor::ModuleVector modules_for_macros; + + for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) + { + modules_for_macros.push_back(module); + } + + if (m_target->GetEnableAutoImportClangModules()) + { + if (StackFrame *frame = exe_ctx.GetFramePtr()) + { + if (Block *block = frame->GetFrameBlock()) + { + SymbolContext sc; + + block->CalculateSymbolContext(&sc); + + if (sc.comp_unit) + { + StreamString error_stream; + + decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros, error_stream); + } + } + } + } + + decl_vendor->ForEachMacro(modules_for_macros, [log, &prefix] (const std::string &expansion) -> bool { prefix.append(expansion); prefix.append("\n"); return false; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp index ef1b037..545476c 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -446,6 +446,31 @@ DWARFCompileUnit::BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data, } } + if (debug_aranges->IsEmpty()) + { + // We got nothing from the functions, maybe we have a line tables only + // situation. Check the line tables and build the arange table from this. + SymbolContext sc; + sc.comp_unit = dwarf2Data->GetCompUnitForDWARFCompUnit(this); + if (sc.comp_unit) + { + LineTable *line_table = sc.comp_unit->GetLineTable(); + + if (line_table) + { + LineTable::FileAddressRanges file_ranges; + const bool append = true; + const size_t num_ranges = line_table->GetContiguousFileAddressRanges (file_ranges, append); + for (uint32_t idx=0; idxAppendRange(GetOffset(), range.GetRangeBase(), range.GetRangeEnd()); + printf ("0x%8.8x: [0x%16.16llx - 0x%16.16llx)\n", GetOffset(), range.GetRangeBase(), range.GetRangeEnd()); + } + } + } + } + // Keep memory down by clearing DIEs if this generate function // caused them to be parsed if (clear_dies) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 28bfcb9..19faac4 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -27,6 +27,8 @@ #include "llvm/Support/Casting.h" #include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Core/Scalar.h" @@ -36,6 +38,8 @@ #include "lldb/Core/Timer.h" #include "lldb/Core/Value.h" +#include "lldb/Expression/ClangModulesDeclVendor.h" + #include "lldb/Host/Host.h" #include "lldb/Symbol/Block.h" @@ -515,6 +519,7 @@ SymbolFileDWARF::SymbolFileDWARF(ObjectFile* objfile) : m_indexed (false), m_is_external_ast_source (false), m_using_apple_tables (false), + m_fetched_external_modules (false), m_supports_DW_AT_APPLE_objc_complete_type (eLazyBoolCalculate), m_ranges(), m_unique_ast_type_map () @@ -1263,6 +1268,25 @@ SymbolFileDWARF::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpec return false; } +bool +SymbolFileDWARF::ParseImportedModules (const lldb_private::SymbolContext &sc, std::vector &imported_modules) +{ + assert (sc.comp_unit); + DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + if (dwarf_cu) + { + if (ClangModulesDeclVendor::LanguageSupportsClangModules(sc.comp_unit->GetLanguage())) + { + UpdateExternalModuleListIfNeeded(); + for (const std::pair &external_type_module : m_external_type_modules) + { + imported_modules.push_back(external_type_module.second.m_name); + } + } + } + return false; +} + struct ParseDWARFLineTableCallbackInfo { LineTable* line_table; @@ -2845,7 +2869,60 @@ SymbolFileDWARF::GetFunction (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEn return false; } - +void +SymbolFileDWARF::UpdateExternalModuleListIfNeeded() +{ + if (m_fetched_external_modules) + return; + m_fetched_external_modules = true; + + DWARFDebugInfo * debug_info = DebugInfo(); + debug_info->GetNumCompileUnits(); + + const uint32_t num_compile_units = GetNumCompileUnits(); + for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) + { + DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); + + const DWARFDebugInfoEntry *die = dwarf_cu->GetCompileUnitDIEOnly(); + if (die && die->HasChildren() == false) + { + const uint64_t name_strp = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_name, UINT64_MAX); + const uint64_t dwo_path_strp = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_GNU_dwo_name, UINT64_MAX); + + if (name_strp != UINT64_MAX) + { + if (m_external_type_modules.find(dwo_path_strp) == m_external_type_modules.end()) + { + const char *name = get_debug_str_data().PeekCStr(name_strp); + const char *dwo_path = get_debug_str_data().PeekCStr(dwo_path_strp); + if (name || dwo_path) + { + ModuleSP module_sp; + if (dwo_path) + { + ModuleSpec dwo_module_spec; + dwo_module_spec.GetFileSpec().SetFile(dwo_path, false); + dwo_module_spec.GetArchitecture() = m_obj_file->GetModule()->GetArchitecture(); + //printf ("Loading dwo = '%s'\n", dwo_path); + Error error = ModuleList::GetSharedModule (dwo_module_spec, module_sp, NULL, NULL, NULL); + } + + if (dwo_path_strp != LLDB_INVALID_UID) + { + m_external_type_modules[dwo_path_strp] = ClangModuleInfo { ConstString(name), module_sp }; + } + else + { + // This hack should be removed promptly once clang emits both. + m_external_type_modules[name_strp] = ClangModuleInfo { ConstString(name), module_sp }; + } + } + } + } + } + } +} SymbolFileDWARF::GlobalVariableMap & SymbolFileDWARF::GetGlobalAranges() diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 1bf5c0d..2f0b3f0 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -103,6 +103,7 @@ public: virtual size_t ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc); virtual bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc); virtual bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList& support_files); + virtual bool ParseImportedModules (const lldb_private::SymbolContext &sc, std::vector &imported_modules); virtual size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc); virtual size_t ParseTypes (const lldb_private::SymbolContext& sc); virtual size_t ParseVariablesForContext (const lldb_private::SymbolContext& sc); @@ -547,6 +548,13 @@ protected: FixupAddress (lldb_private::Address &addr); typedef std::set TypeSet; + + typedef struct { + lldb_private::ConstString m_name; + lldb::ModuleSP m_module_sp; + } ClangModuleInfo; + + typedef std::map ExternalTypeModuleMap; void GetTypes (DWARFCompileUnit* dwarf_cu, @@ -560,6 +568,9 @@ protected: GlobalVariableMap & GetGlobalAranges(); + + void + UpdateExternalModuleListIfNeeded(); lldb::ModuleWP m_debug_map_module_wp; SymbolFileDWARFDebugMap * m_debug_map_symfile; @@ -589,6 +600,7 @@ protected: std::unique_ptr m_apple_namespaces_ap; std::unique_ptr m_apple_objc_ap; std::unique_ptr m_global_aranges_ap; + ExternalTypeModuleMap m_external_type_modules; NameToDIE m_function_basename_index; // All concrete functions NameToDIE m_function_fullname_index; // All concrete functions NameToDIE m_function_method_index; // All inlined functions @@ -599,7 +611,8 @@ protected: NameToDIE m_namespace_index; // All type DIE offsets bool m_indexed:1, m_is_external_ast_source:1, - m_using_apple_tables:1; + m_using_apple_tables:1, + m_fetched_external_modules:1; lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type; std::unique_ptr m_ranges; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index 3087bde..d5d60ae 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -227,18 +227,11 @@ public: if (exe_objfile && exe_sym_vendor) { - if (oso_symfile->GetNumCompileUnits() == 1) - { - oso_symfile->SetDebugMapModule(exe_module_sp); - // Set the ID of the symbol file DWARF to the index of the OSO - // shifted left by 32 bits to provide a unique prefix for any - // UserID's that get created in the symbol file. - oso_symfile->SetID (((uint64_t)m_cu_idx + 1ull) << 32ull); - } - else - { - oso_symfile->SetID (UINT64_MAX); - } + oso_symfile->SetDebugMapModule(exe_module_sp); + // Set the ID of the symbol file DWARF to the index of the OSO + // shifted left by 32 bits to provide a unique prefix for any + // UserID's that get created in the symbol file. + oso_symfile->SetID (((uint64_t)m_cu_idx + 1ull) << 32ull); } return symbol_vendor; } @@ -743,6 +736,14 @@ SymbolFileDWARFDebugMap::ParseCompileUnitSupportFiles (const SymbolContext& sc, return false; } +bool +SymbolFileDWARFDebugMap::ParseImportedModules (const SymbolContext &sc, std::vector &imported_modules) +{ + SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc); + if (oso_dwarf) + return oso_dwarf->ParseImportedModules(sc, imported_modules); + return false; +} size_t SymbolFileDWARFDebugMap::ParseFunctionBlocks (const SymbolContext& sc) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index 2a6e989..78ec761 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -70,6 +70,7 @@ public: virtual size_t ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc); virtual bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc); virtual bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files); + virtual bool ParseImportedModules (const lldb_private::SymbolContext &sc, std::vector &imported_modules) override; virtual size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc); virtual size_t ParseTypes (const lldb_private::SymbolContext& sc); virtual size_t ParseVariablesForContext (const lldb_private::SymbolContext& sc); diff --git a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp index 8e85d48..8eb3e3a 100644 --- a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp +++ b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp @@ -266,6 +266,12 @@ SymbolFileSymtab::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpe return false; } +bool +SymbolFileSymtab::ParseImportedModules (const SymbolContext &sc, std::vector &imported_modules) +{ + return false; +} + size_t SymbolFileSymtab::ParseFunctionBlocks (const SymbolContext &sc) { diff --git a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h index 914efe6..d606419a 100644 --- a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h +++ b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h @@ -65,6 +65,9 @@ public: virtual bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files); + + virtual bool + ParseImportedModules (const lldb_private::SymbolContext &sc, std::vector &imported_modules); virtual size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc); diff --git a/lldb/source/Symbol/CompileUnit.cpp b/lldb/source/Symbol/CompileUnit.cpp index 6483258..d8e95ce 100644 --- a/lldb/source/Symbol/CompileUnit.cpp +++ b/lldb/source/Symbol/CompileUnit.cpp @@ -436,6 +436,23 @@ CompileUnit::SetVariableList(VariableListSP &variables) m_variables = variables; } +const std::vector & +CompileUnit::GetImportedModules () +{ + if (m_imported_modules.empty() && + m_flags.IsClear(flagsParsedImportedModules)) + { + m_flags.Set(flagsParsedImportedModules); + if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) + { + SymbolContext sc; + CalculateSymbolContext(&sc); + symbol_vendor->ParseImportedModules(sc, m_imported_modules); + } + } + return m_imported_modules; +} + FileSpecList& CompileUnit::GetSupportFiles () { diff --git a/lldb/source/Symbol/SymbolVendor.cpp b/lldb/source/Symbol/SymbolVendor.cpp index 6445efb..6ec9f38 100644 --- a/lldb/source/Symbol/SymbolVendor.cpp +++ b/lldb/source/Symbol/SymbolVendor.cpp @@ -198,6 +198,21 @@ SymbolVendor::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecLis return false; } +bool +SymbolVendor::ParseImportedModules (const SymbolContext &sc, + std::vector &imported_modules) +{ + ModuleSP module_sp(GetModule()); + if (module_sp) + { + lldb_private::Mutex::Locker locker(module_sp->GetMutex()); + if (m_sym_file_ap.get()) + return m_sym_file_ap->ParseImportedModules(sc, imported_modules); + } + return false; + +} + size_t SymbolVendor::ParseFunctionBlocks (const SymbolContext &sc) { diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 400cf47..6042a8f 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -2927,6 +2927,7 @@ g_properties[] = { "exec-search-paths" , OptionValue::eTypeFileSpecList, false, 0 , NULL, NULL, "Executable search paths to use when locating executable files whose paths don't match the local file system." }, { "debug-file-search-paths" , OptionValue::eTypeFileSpecList, false, 0 , NULL, NULL, "List of directories to be searched when locating debug symbol files." }, { "clang-module-search-paths" , OptionValue::eTypeFileSpecList, false, 0 , NULL, NULL, "List of directories to be searched when locating modules for Clang." }, + { "auto-import-clang-modules" , OptionValue::eTypeBoolean , false, false , NULL, NULL, "Automatically load Clang modules referred to by the program." }, { "max-children-count" , OptionValue::eTypeSInt64 , false, 256 , NULL, NULL, "Maximum number of children to expand in any level of depth." }, { "max-string-summary-length" , OptionValue::eTypeSInt64 , false, 1024 , NULL, NULL, "Maximum number of characters to show when using %s in summary strings." }, { "max-memory-read-size" , OptionValue::eTypeSInt64 , false, 1024 , NULL, NULL, "Maximum number of bytes that 'memory read' will fetch before --force must be specified." }, @@ -2978,6 +2979,7 @@ enum ePropertyExecutableSearchPaths, ePropertyDebugFileSearchPaths, ePropertyClangModuleSearchPaths, + ePropertyAutoImportClangModules, ePropertyMaxChildrenCount, ePropertyMaxSummaryLength, ePropertyMaxMemReadSize, @@ -3332,6 +3334,13 @@ TargetProperties::GetClangModuleSearchPaths () } bool +TargetProperties::GetEnableAutoImportClangModules() const +{ + const uint32_t idx = ePropertyAutoImportClangModules; + return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); +} + +bool TargetProperties::GetEnableSyntheticValue () const { const uint32_t idx = ePropertyEnableSynthetic; diff --git a/lldb/test/functionalities/data-formatter/typedef_array/Makefile b/lldb/test/functionalities/data-formatter/typedef_array/Makefile index 3e2b018..e69de29 100644 --- a/lldb/test/functionalities/data-formatter/typedef_array/Makefile +++ b/lldb/test/functionalities/data-formatter/typedef_array/Makefile @@ -1,4 +0,0 @@ -LEVEL = ../../../make -CXX_SOURCES := main.cpp -CXXFLAGS += -std=c++11 -include $(LEVEL)/Makefile.rules diff --git a/lldb/test/lang/objc/modules-auto-import/Makefile b/lldb/test/lang/objc/modules-auto-import/Makefile new file mode 100644 index 0000000..e42b59f --- /dev/null +++ b/lldb/test/lang/objc/modules-auto-import/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../../make +OBJC_SOURCES := main.m + +CFLAGS += -fmodules -gmodules -g + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/lang/objc/modules-auto-import/TestModulesAutoImport.py b/lldb/test/lang/objc/modules-auto-import/TestModulesAutoImport.py new file mode 100644 index 0000000..997b4ee --- /dev/null +++ b/lldb/test/lang/objc/modules-auto-import/TestModulesAutoImport.py @@ -0,0 +1,78 @@ +"""Test that importing modules in Objective-C works as expected.""" + +import os, time +import unittest2 +import lldb +import platform +import lldbutil + +from distutils.version import StrictVersion + +from lldbtest import * + +class ObjCModulesAutoImportTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipUnlessDarwin + @dsym_test + @unittest2.expectedFailure("rdar://problem/19991953") + def test_expr_with_dsym(self): + self.buildDsym() + self.expr() + + @dwarf_test + @skipIfFreeBSD + @skipIfLinux + def test_expr_with_dwarf(self): + self.buildDwarf() + self.expr() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break inside main(). + self.line = line_number('main.m', '// Set breakpoint 0 here.') + + def applies(self): + if platform.system() != "Darwin": + return False + if StrictVersion('12.0.0') > platform.release(): + return False + + return True + + def common_setup(self): + exe = os.path.join(os.getcwd(), "a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + # Break inside the foo function which takes a bar_ptr argument. + lldbutil.run_break_set_by_file_and_line (self, "main.m", self.line, num_expected_locations=1, loc_exact=True) + + self.runCmd("run", RUN_SUCCEEDED) + + # The stop reason of the thread should be breakpoint. + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs = ['stopped', + 'stop reason = breakpoint']) + + # The breakpoint should have a hit count of 1. + self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE, + substrs = [' resolved, hit count = 1']) + + def expr(self): + if not self.applies(): + return + + self.common_setup() + + self.runCmd("settings set target.auto-import-clang-modules true") + + self.expect("p getpid()", VARIABLES_DISPLAYED_CORRECTLY, + substrs = ["pid_t"]) + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/lang/objc/modules-auto-import/main.m b/lldb/test/lang/objc/modules-auto-import/main.m new file mode 100644 index 0000000..5452ffd --- /dev/null +++ b/lldb/test/lang/objc/modules-auto-import/main.m @@ -0,0 +1,7 @@ +@import Darwin; + +int main() +{ + size_t ret = printf("Stop here\n"); // Set breakpoint 0 here. + return ret; +} diff --git a/lldb/test/lang/objc/modules-incomplete/TestIncompleteModules.py b/lldb/test/lang/objc/modules-incomplete/TestIncompleteModules.py index af7cffd..b552fd5 100644 --- a/lldb/test/lang/objc/modules-incomplete/TestIncompleteModules.py +++ b/lldb/test/lang/objc/modules-incomplete/TestIncompleteModules.py @@ -75,6 +75,12 @@ class IncompleteModulesTestCase(TestBase): self.expect("expr [myObject privateMethod]", VARIABLES_DISPLAYED_CORRECTLY, substrs = ["int", "5"]) + self.expect("expr MIN(2,3)", "#defined macro was found", + substrs = ["int", "2"]) + + self.expect("expr MAX(2,3)", "#undefd macro was correcltly not found", + error=True) + if __name__ == '__main__': import atexit lldb.SBDebugger.Initialize() diff --git a/lldb/test/lang/objc/modules-incomplete/myModule.h b/lldb/test/lang/objc/modules-incomplete/myModule.h index 8f28ce0..d03dde0 100644 --- a/lldb/test/lang/objc/modules-incomplete/myModule.h +++ b/lldb/test/lang/objc/modules-incomplete/myModule.h @@ -1,5 +1,7 @@ @import Foundation; +#undef MAX + @interface MyClass : NSObject { }; -(void)publicMethod; -- 2.7.4