//===-- DiagnosticManager.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/Expression/DiagnosticManager.h" #include "llvm/Support/ErrorHandling.h" #include "lldb/Utility/ErrorMessages.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" using namespace lldb_private; char ExpressionError::ID; /// A std::error_code category for eErrorTypeExpression. class ExpressionCategory : public std::error_category { const char *name() const noexcept override { return "LLDBExpressionCategory"; } std::string message(int __ev) const override { return toString(static_cast(__ev)); }; }; ExpressionCategory &expression_category() { static ExpressionCategory g_expression_category; return g_expression_category; } ExpressionError::ExpressionError(lldb::ExpressionResults result, std::string msg, std::vector details) : ErrorInfo(std::error_code(result, expression_category())), m_message(msg), m_details(details) {} static llvm::StringRef StringForSeverity(lldb::Severity severity) { switch (severity) { // this should be exhaustive case lldb::eSeverityError: return "error: "; case lldb::eSeverityWarning: return "warning: "; case lldb::eSeverityInfo: return ""; } llvm_unreachable("switch needs another case for lldb::Severity enum"); } std::string ExpressionError::message() const { std::string str; { llvm::raw_string_ostream os(str); if (!m_message.empty()) os << m_message << '\n'; for (const auto &detail : m_details) os << StringForSeverity(detail.severity) << detail.rendered << '\n'; } return str; } std::error_code ExpressionError::convertToErrorCode() const { return llvm::inconvertibleErrorCode(); } void ExpressionError::log(llvm::raw_ostream &OS) const { OS << message(); } std::unique_ptr ExpressionError::Clone() const { return std::make_unique( (lldb::ExpressionResults)convertToErrorCode().value(), m_message, m_details); } std::string DiagnosticManager::GetString(char separator) { std::string str; llvm::raw_string_ostream stream(str); for (const auto &diagnostic : Diagnostics()) { llvm::StringRef severity = StringForSeverity(diagnostic->GetSeverity()); stream << severity; llvm::StringRef message = diagnostic->GetMessage(); auto severity_pos = message.find(severity); stream << message.take_front(severity_pos); if (severity_pos != llvm::StringRef::npos) stream << message.drop_front(severity_pos + severity.size()); stream << separator; } return str; } void DiagnosticManager::Dump(Log *log) { if (!log) return; std::string str = GetString(); // We want to remove the last '\n' because log->PutCString will add // one for us. if (!str.empty() && str.back() == '\n') str.pop_back(); log->PutString(str); } llvm::Error DiagnosticManager::GetAsError(lldb::ExpressionResults result, llvm::Twine message) const { std::vector details; for (const auto &diag : m_diagnostics) details.push_back(diag->GetDetail()); return llvm::make_error(result, message.str(), details); } void DiagnosticManager::AddDiagnostic(llvm::StringRef message, lldb::Severity severity, DiagnosticOrigin origin, uint32_t compiler_id) { m_diagnostics.emplace_back(std::make_unique( origin, compiler_id, DiagnosticDetail{{}, severity, message.str(), message.str()})); } size_t DiagnosticManager::Printf(lldb::Severity severity, const char *format, ...) { StreamString ss; va_list args; va_start(args, format); size_t result = ss.PrintfVarArg(format, args); va_end(args); AddDiagnostic(ss.GetString(), severity, eDiagnosticOriginLLDB); return result; } void DiagnosticManager::PutString(lldb::Severity severity, llvm::StringRef str) { if (str.empty()) return; AddDiagnostic(str, severity, eDiagnosticOriginLLDB); } void Diagnostic::AppendMessage(llvm::StringRef message, bool precede_with_newline) { if (precede_with_newline) { m_detail.message.push_back('\n'); m_detail.rendered.push_back('\n'); } m_detail.message += message; m_detail.rendered += message; }