diff options
Diffstat (limited to 'source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp')
-rw-r--r-- | source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp | 285 |
1 files changed, 146 insertions, 139 deletions
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 7d13891ded8d..1422911d6546 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -105,16 +105,26 @@ using namespace lldb_private; class ClangExpressionParser::LLDBPreprocessorCallbacks : public PPCallbacks { ClangModulesDeclVendor &m_decl_vendor; ClangPersistentVariables &m_persistent_vars; + clang::SourceManager &m_source_mgr; StreamString m_error_stream; bool m_has_errors = false; public: LLDBPreprocessorCallbacks(ClangModulesDeclVendor &decl_vendor, - ClangPersistentVariables &persistent_vars) - : m_decl_vendor(decl_vendor), m_persistent_vars(persistent_vars) {} + ClangPersistentVariables &persistent_vars, + clang::SourceManager &source_mgr) + : m_decl_vendor(decl_vendor), m_persistent_vars(persistent_vars), + m_source_mgr(source_mgr) {} void moduleImport(SourceLocation import_location, clang::ModuleIdPath path, const clang::Module * /*null*/) override { + // Ignore modules that are imported in the wrapper code as these are not + // loaded by the user. + llvm::StringRef filename = + m_source_mgr.getPresumedLoc(import_location).getFilename(); + if (filename == ClangExpressionSourceCode::g_prefix_file_name) + return; + SourceModule module; for (const std::pair<IdentifierInfo *, SourceLocation> &component : path) @@ -137,12 +147,14 @@ public: class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer { public: - ClangDiagnosticManagerAdapter() - : m_passthrough(new clang::TextDiagnosticBuffer) {} - - ClangDiagnosticManagerAdapter( - const std::shared_ptr<clang::TextDiagnosticBuffer> &passthrough) - : m_passthrough(passthrough) {} + ClangDiagnosticManagerAdapter(DiagnosticOptions &opts) { + DiagnosticOptions *m_options = new DiagnosticOptions(opts); + m_options->ShowPresumedLoc = true; + m_options->ShowLevel = false; + m_os.reset(new llvm::raw_string_ostream(m_output)); + m_passthrough.reset( + new clang::TextDiagnosticPrinter(*m_os, m_options, false)); + } void ResetManager(DiagnosticManager *manager = nullptr) { m_manager = manager; @@ -150,79 +162,92 @@ public: void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override { - if (m_manager) { - llvm::SmallVector<char, 32> diag_str; - Info.FormatDiagnostic(diag_str); - diag_str.push_back('\0'); - const char *data = diag_str.data(); - - lldb_private::DiagnosticSeverity severity; - bool make_new_diagnostic = true; - - switch (DiagLevel) { - case DiagnosticsEngine::Level::Fatal: - case DiagnosticsEngine::Level::Error: - severity = eDiagnosticSeverityError; - break; - case DiagnosticsEngine::Level::Warning: - severity = eDiagnosticSeverityWarning; - break; - case DiagnosticsEngine::Level::Remark: - case DiagnosticsEngine::Level::Ignored: - severity = eDiagnosticSeverityRemark; - break; - case DiagnosticsEngine::Level::Note: - m_manager->AppendMessageToDiagnostic(data); - make_new_diagnostic = false; - } - if (make_new_diagnostic) { - ClangDiagnostic *new_diagnostic = - new ClangDiagnostic(data, severity, Info.getID()); - m_manager->AddDiagnostic(new_diagnostic); - - // Don't store away warning fixits, since the compiler doesn't have - // enough context in an expression for the warning to be useful. - // FIXME: Should we try to filter out FixIts that apply to our generated - // code, and not the user's expression? - if (severity == eDiagnosticSeverityError) { - size_t num_fixit_hints = Info.getNumFixItHints(); - for (size_t i = 0; i < num_fixit_hints; i++) { - const clang::FixItHint &fixit = Info.getFixItHint(i); - if (!fixit.isNull()) - new_diagnostic->AddFixitHint(fixit); - } - } + if (!m_manager) { + // We have no DiagnosticManager before/after parsing but we still could + // receive diagnostics (e.g., by the ASTImporter failing to copy decls + // when we move the expression result ot the ScratchASTContext). Let's at + // least log these diagnostics until we find a way to properly render + // them and display them to the user. + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + if (log) { + llvm::SmallVector<char, 32> diag_str; + Info.FormatDiagnostic(diag_str); + diag_str.push_back('\0'); + const char *plain_diag = diag_str.data(); + LLDB_LOG(log, "Received diagnostic outside parsing: {0}", plain_diag); } + return; } + // Render diagnostic message to m_output. + m_output.clear(); m_passthrough->HandleDiagnostic(DiagLevel, Info); - } + m_os->flush(); - void FlushDiagnostics(DiagnosticsEngine &Diags) { - m_passthrough->FlushDiagnostics(Diags); - } + lldb_private::DiagnosticSeverity severity; + bool make_new_diagnostic = true; + + switch (DiagLevel) { + case DiagnosticsEngine::Level::Fatal: + case DiagnosticsEngine::Level::Error: + severity = eDiagnosticSeverityError; + break; + case DiagnosticsEngine::Level::Warning: + severity = eDiagnosticSeverityWarning; + break; + case DiagnosticsEngine::Level::Remark: + case DiagnosticsEngine::Level::Ignored: + severity = eDiagnosticSeverityRemark; + break; + case DiagnosticsEngine::Level::Note: + m_manager->AppendMessageToDiagnostic(m_output); + make_new_diagnostic = false; + } + if (make_new_diagnostic) { + // ClangDiagnostic messages are expected to have no whitespace/newlines + // around them. + std::string stripped_output = llvm::StringRef(m_output).trim(); + + auto new_diagnostic = std::make_unique<ClangDiagnostic>( + stripped_output, severity, Info.getID()); + + // Don't store away warning fixits, since the compiler doesn't have + // enough context in an expression for the warning to be useful. + // FIXME: Should we try to filter out FixIts that apply to our generated + // code, and not the user's expression? + if (severity == eDiagnosticSeverityError) { + size_t num_fixit_hints = Info.getNumFixItHints(); + for (size_t i = 0; i < num_fixit_hints; i++) { + const clang::FixItHint &fixit = Info.getFixItHint(i); + if (!fixit.isNull()) + new_diagnostic->AddFixitHint(fixit); + } + } - DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { - return new ClangDiagnosticManagerAdapter(m_passthrough); + m_manager->AddDiagnostic(std::move(new_diagnostic)); + } } - clang::TextDiagnosticBuffer *GetPassthrough() { return m_passthrough.get(); } + clang::TextDiagnosticPrinter *GetPassthrough() { return m_passthrough.get(); } private: DiagnosticManager *m_manager = nullptr; - std::shared_ptr<clang::TextDiagnosticBuffer> m_passthrough; + std::shared_ptr<clang::TextDiagnosticPrinter> m_passthrough; + /// Output stream of m_passthrough. + std::shared_ptr<llvm::raw_string_ostream> m_os; + /// Output string filled by m_os. + std::string m_output; }; -static void -SetupModuleHeaderPaths(CompilerInstance *compiler, - std::vector<ConstString> include_directories, - lldb::TargetSP target_sp) { +static void SetupModuleHeaderPaths(CompilerInstance *compiler, + std::vector<std::string> include_directories, + lldb::TargetSP target_sp) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); HeaderSearchOptions &search_opts = compiler->getHeaderSearchOpts(); - for (ConstString dir : include_directories) { - search_opts.AddPath(dir.AsCString(), frontend::System, false, true); + for (const std::string &dir : include_directories) { + search_opts.AddPath(dir, frontend::System, false, true); LLDB_LOG(log, "Added user include dir: {0}", dir); } @@ -232,27 +257,9 @@ SetupModuleHeaderPaths(CompilerInstance *compiler, search_opts.ModuleCachePath = module_cache.str(); LLDB_LOG(log, "Using module cache path: {0}", module_cache.c_str()); - FileSpec clang_resource_dir = GetClangResourceDir(); - std::string resource_dir = clang_resource_dir.GetPath(); - if (FileSystem::Instance().IsDirectory(resource_dir)) { - search_opts.ResourceDir = resource_dir; - std::string resource_include = resource_dir + "/include"; - search_opts.AddPath(resource_include, frontend::System, false, true); - - LLDB_LOG(log, "Added resource include dir: {0}", resource_include); - } + search_opts.ResourceDir = GetClangResourceDir().GetPath(); search_opts.ImplicitModuleMaps = true; - - std::vector<std::string> system_include_directories = - target_sp->GetPlatform()->GetSystemIncludeDirectories( - lldb::eLanguageTypeC_plus_plus); - - for (const std::string &include_dir : system_include_directories) { - search_opts.AddPath(include_dir, frontend::System, false, true); - - LLDB_LOG(log, "Added system include dir: {0}", include_dir); - } } //===----------------------------------------------------------------------===// @@ -261,10 +268,12 @@ SetupModuleHeaderPaths(CompilerInstance *compiler, ClangExpressionParser::ClangExpressionParser( ExecutionContextScope *exe_scope, Expression &expr, - bool generate_debug_info, std::vector<ConstString> include_directories) + bool generate_debug_info, std::vector<std::string> include_directories, + std::string filename) : ExpressionParser(exe_scope, expr, generate_debug_info), m_compiler(), m_pp_callbacks(nullptr), - m_include_directories(std::move(include_directories)) { + m_include_directories(std::move(include_directories)), + m_filename(std::move(filename)) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // We can't compile expressions without a target. So if the exe_scope is @@ -331,9 +340,8 @@ ClangExpressionParser::ClangExpressionParser( if (process_sp && frame_lang != lldb::eLanguageTypeUnknown) { lang_rt = process_sp->GetLanguageRuntime(frame_lang); - if (log) - log->Printf("Frame has language of type %s", - Language::GetNameForLanguageType(frame_lang)); + LLDB_LOGF(log, "Frame has language of type %s", + Language::GetNameForLanguageType(frame_lang)); } // 2. Configure the compiler with a set of default options that are @@ -341,9 +349,8 @@ ClangExpressionParser::ClangExpressionParser( if (target_arch.IsValid()) { std::string triple = target_arch.GetTriple().str(); m_compiler->getTargetOpts().Triple = triple; - if (log) - log->Printf("Using %s as the target triple", - m_compiler->getTargetOpts().Triple.c_str()); + LLDB_LOGF(log, "Using %s as the target triple", + m_compiler->getTargetOpts().Triple.c_str()); } else { // If we get here we don't have a valid target and just have to guess. // Sometimes this will be ok to just use the host target triple (when we @@ -352,9 +359,8 @@ ClangExpressionParser::ClangExpressionParser( // the host triple. In such a case the language runtime should expose an // overridden options set (3), below. m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple(); - if (log) - log->Printf("Using default target triple of %s", - m_compiler->getTargetOpts().Triple.c_str()); + LLDB_LOGF(log, "Using default target triple of %s", + m_compiler->getTargetOpts().Triple.c_str()); } // Now add some special fixes for known architectures: Any arm32 iOS // environment, but not on arm64 @@ -408,12 +414,13 @@ ClangExpressionParser::ClangExpressionParser( auto target_info = TargetInfo::CreateTargetInfo( m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts); if (log) { - log->Printf("Using SIMD alignment: %d", target_info->getSimdDefaultAlign()); - log->Printf("Target datalayout string: '%s'", - target_info->getDataLayout().getStringRepresentation().c_str()); - log->Printf("Target ABI: '%s'", target_info->getABI().str().c_str()); - log->Printf("Target vector alignment: %d", - target_info->getMaxVectorAlign()); + LLDB_LOGF(log, "Using SIMD alignment: %d", + target_info->getSimdDefaultAlign()); + LLDB_LOGF(log, "Target datalayout string: '%s'", + target_info->getDataLayout().getStringRepresentation().c_str()); + LLDB_LOGF(log, "Target ABI: '%s'", target_info->getABI().str().c_str()); + LLDB_LOGF(log, "Target vector alignment: %d", + target_info->getMaxVectorAlign()); } m_compiler->setTarget(target_info); @@ -508,6 +515,9 @@ ClangExpressionParser::ClangExpressionParser( lang_opts.DoubleSquareBracketAttributes = true; lang_opts.CPlusPlus11 = true; + // The Darwin libc expects this macro to be set. + lang_opts.GNUCVersion = 40201; + SetupModuleHeaderPaths(m_compiler.get(), m_include_directories, target_sp); } @@ -537,8 +547,8 @@ ClangExpressionParser::ClangExpressionParser( // Set CodeGen options m_compiler->getCodeGenOpts().EmitDeclMetadata = true; m_compiler->getCodeGenOpts().InstrumentFunctions = false; - m_compiler->getCodeGenOpts().DisableFPElim = true; - m_compiler->getCodeGenOpts().OmitLeafFramePointer = false; + m_compiler->getCodeGenOpts().setFramePointer( + CodeGenOptions::FramePointerKind::All); if (generate_debug_info) m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo); else @@ -560,7 +570,9 @@ ClangExpressionParser::ClangExpressionParser( // 6. Set up the diagnostic buffer for reporting errors - m_compiler->getDiagnostics().setClient(new ClangDiagnosticManagerAdapter); + auto diag_mgr = new ClangDiagnosticManagerAdapter( + m_compiler->getDiagnostics().getDiagnosticOptions()); + m_compiler->getDiagnostics().setClient(diag_mgr); // 7. Set up the source management objects inside the compiler m_compiler->createFileManager(); @@ -574,8 +586,8 @@ ClangExpressionParser::ClangExpressionParser( llvm::cast<ClangPersistentVariables>( target_sp->GetPersistentExpressionStateForLanguage( lldb::eLanguageTypeC)); - std::unique_ptr<PPCallbacks> pp_callbacks( - new LLDBPreprocessorCallbacks(*decl_vendor, *clang_persistent_vars)); + std::unique_ptr<PPCallbacks> pp_callbacks(new LLDBPreprocessorCallbacks( + *decl_vendor, *clang_persistent_vars, m_compiler->getSourceManager())); m_pp_callbacks = static_cast<LLDBPreprocessorCallbacks *>(pp_callbacks.get()); m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks)); @@ -592,9 +604,7 @@ ClangExpressionParser::ClangExpressionParser( m_compiler->createASTContext(); clang::ASTContext &ast_context = m_compiler->getASTContext(); - m_ast_context.reset( - new ClangASTContext(m_compiler->getTargetOpts().Triple.c_str())); - m_ast_context->setASTContext(&ast_context); + m_ast_context.reset(new ClangASTContext(ast_context)); std::string module_name("$__lldb_module"); @@ -872,8 +882,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, ClangDiagnosticManagerAdapter *adapter = static_cast<ClangDiagnosticManagerAdapter *>( m_compiler->getDiagnostics().getClient()); - clang::TextDiagnosticBuffer *diag_buf = adapter->GetPassthrough(); - diag_buf->FlushDiagnostics(m_compiler->getDiagnostics()); + auto diag_buf = adapter->GetPassthrough(); adapter->ResetManager(&diagnostic_manager); @@ -904,16 +913,19 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, } if (temp_fd != -1) { - lldb_private::File file(temp_fd, true); + lldb_private::NativeFile file(temp_fd, File::eOpenOptionWrite, true); const size_t expr_text_len = strlen(expr_text); size_t bytes_written = expr_text_len; if (file.Write(expr_text, bytes_written).Success()) { if (bytes_written == expr_text_len) { file.Close(); - source_mgr.setMainFileID(source_mgr.createFileID( - m_compiler->getFileManager().getFile(result_path), - SourceLocation(), SrcMgr::C_User)); - created_main_file = true; + if (auto fileEntry = + m_compiler->getFileManager().getFile(result_path)) { + source_mgr.setMainFileID(source_mgr.createFileID( + *fileEntry, + SourceLocation(), SrcMgr::C_User)); + created_main_file = true; + } } } } @@ -921,7 +933,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, if (!created_main_file) { std::unique_ptr<MemoryBuffer> memory_buffer = - MemoryBuffer::getMemBufferCopy(expr_text, "<lldb-expr>"); + MemoryBuffer::getMemBufferCopy(expr_text, m_filename); source_mgr.setMainFileID(source_mgr.createFileID(std::move(memory_buffer))); } @@ -1092,8 +1104,8 @@ bool ClangExpressionParser::RewriteExpression( if (num_diags == 0) return false; - for (const Diagnostic *diag : diagnostic_manager.Diagnostics()) { - const ClangDiagnostic *diagnostic = llvm::dyn_cast<ClangDiagnostic>(diag); + for (const auto &diag : diagnostic_manager.Diagnostics()) { + const auto *diagnostic = llvm::dyn_cast<ClangDiagnostic>(diag.get()); if (diagnostic && diagnostic->HasFixIts()) { for (const FixItHint &fixit : diagnostic->FixIts()) { // This is cobbed from clang::Rewrite::FixItRewriter. @@ -1181,9 +1193,8 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( m_expr.FunctionName()); return err; } else { - if (log) - log->Printf("Found function %s for %s", function_name.AsCString(), - m_expr.FunctionName()); + LLDB_LOGF(log, "Found function %s for %s", function_name.AsCString(), + m_expr.FunctionName()); } } @@ -1198,9 +1209,8 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( LLVMUserExpression::IRPasses custom_passes; { auto lang = m_expr.Language(); - if (log) - log->Printf("%s - Current expression language is %s\n", __FUNCTION__, - Language::GetNameForLanguageType(lang)); + LLDB_LOGF(log, "%s - Current expression language is %s\n", __FUNCTION__, + Language::GetNameForLanguageType(lang)); lldb::ProcessSP process_sp = exe_ctx.GetProcessSP(); if (process_sp && lang != lldb::eLanguageTypeUnknown) { auto runtime = process_sp->GetLanguageRuntime(lang); @@ -1210,10 +1220,10 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( } if (custom_passes.EarlyPasses) { - if (log) - log->Printf("%s - Running Early IR Passes from LanguageRuntime on " - "expression module '%s'", - __FUNCTION__, m_expr.FunctionName()); + LLDB_LOGF(log, + "%s - Running Early IR Passes from LanguageRuntime on " + "expression module '%s'", + __FUNCTION__, m_expr.FunctionName()); custom_passes.EarlyPasses->run(*llvm_module_up); } @@ -1230,12 +1240,10 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( type_system_helper->DeclMap(); // result can be NULL if (decl_map) { - Stream *error_stream = nullptr; Target *target = exe_ctx.GetTargetPtr(); - error_stream = target->GetDebugger().GetErrorFile().get(); - + auto &error_stream = target->GetDebugger().GetErrorStream(); IRForTarget ir_for_target(decl_map, m_expr.NeedsVariableResolution(), - *execution_unit_sp, *error_stream, + *execution_unit_sp, error_stream, function_name.AsCString()); bool ir_can_run = @@ -1298,9 +1306,8 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( process->SetDynamicCheckers(dynamic_checkers); - if (log) - log->Printf("== [ClangExpressionParser::PrepareForExecution] " - "Finished installing dynamic checkers =="); + LLDB_LOGF(log, "== [ClangExpressionParser::PrepareForExecution] " + "Finished installing dynamic checkers =="); } if (auto *checker_funcs = llvm::dyn_cast<ClangDynamicCheckerFunctions>( @@ -1316,10 +1323,10 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( } if (custom_passes.LatePasses) { - if (log) - log->Printf("%s - Running Late IR Passes from LanguageRuntime on " - "expression module '%s'", - __FUNCTION__, m_expr.FunctionName()); + LLDB_LOGF(log, + "%s - Running Late IR Passes from LanguageRuntime on " + "expression module '%s'", + __FUNCTION__, m_expr.FunctionName()); custom_passes.LatePasses->run(*module); } |