1 //===-- DiagnosticManager.cpp ---------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Expression/DiagnosticManager.h" 10 11 #include "llvm/Support/ErrorHandling.h" 12 13 #include "lldb/Utility/ErrorMessages.h" 14 #include "lldb/Utility/Log.h" 15 #include "lldb/Utility/StreamString.h" 16 17 using namespace lldb_private; 18 char ExpressionError::ID; 19 20 /// A std::error_code category for eErrorTypeExpression. 21 class ExpressionCategory : public std::error_category { 22 const char *name() const noexcept override { 23 return "LLDBExpressionCategory"; 24 } 25 std::string message(int __ev) const override { 26 return toString(static_cast<lldb::ExpressionResults>(__ev)); 27 }; 28 }; 29 ExpressionCategory &expression_category() { 30 static ExpressionCategory g_expression_category; 31 return g_expression_category; 32 } 33 34 ExpressionError::ExpressionError(lldb::ExpressionResults result, 35 std::string msg, 36 std::vector<DiagnosticDetail> details) 37 : ErrorInfo(std::error_code(result, expression_category())), m_message(msg), 38 m_details(details) {} 39 40 static llvm::StringRef StringForSeverity(lldb::Severity severity) { 41 switch (severity) { 42 // this should be exhaustive 43 case lldb::eSeverityError: 44 return "error: "; 45 case lldb::eSeverityWarning: 46 return "warning: "; 47 case lldb::eSeverityInfo: 48 return ""; 49 } 50 llvm_unreachable("switch needs another case for lldb::Severity enum"); 51 } 52 53 std::string ExpressionError::message() const { 54 std::string str; 55 { 56 llvm::raw_string_ostream os(str); 57 if (!m_message.empty()) 58 os << m_message << '\n'; 59 for (const auto &detail : m_details) 60 os << StringForSeverity(detail.severity) << detail.rendered << '\n'; 61 } 62 return str; 63 } 64 65 std::error_code ExpressionError::convertToErrorCode() const { 66 return llvm::inconvertibleErrorCode(); 67 } 68 69 void ExpressionError::log(llvm::raw_ostream &OS) const { OS << message(); } 70 71 std::unique_ptr<CloneableError> ExpressionError::Clone() const { 72 return std::make_unique<ExpressionError>( 73 (lldb::ExpressionResults)convertToErrorCode().value(), m_message, 74 m_details); 75 } 76 77 std::string DiagnosticManager::GetString(char separator) { 78 std::string str; 79 llvm::raw_string_ostream stream(str); 80 81 for (const auto &diagnostic : Diagnostics()) { 82 llvm::StringRef severity = StringForSeverity(diagnostic->GetSeverity()); 83 stream << severity; 84 85 llvm::StringRef message = diagnostic->GetMessage(); 86 std::string searchable_message = message.lower(); 87 auto severity_pos = message.find(severity); 88 stream << message.take_front(severity_pos); 89 90 if (severity_pos != llvm::StringRef::npos) 91 stream << message.drop_front(severity_pos + severity.size()); 92 stream << separator; 93 } 94 return str; 95 } 96 97 void DiagnosticManager::Dump(Log *log) { 98 if (!log) 99 return; 100 101 std::string str = GetString(); 102 103 // We want to remove the last '\n' because log->PutCString will add 104 // one for us. 105 106 if (!str.empty() && str.back() == '\n') 107 str.pop_back(); 108 109 log->PutString(str); 110 } 111 112 llvm::Error DiagnosticManager::GetAsError(lldb::ExpressionResults result, 113 llvm::Twine message) const { 114 std::vector<DiagnosticDetail> details; 115 for (const auto &diag : m_diagnostics) 116 details.push_back(diag->GetDetail()); 117 return llvm::make_error<ExpressionError>(result, message.str(), details); 118 } 119 120 void DiagnosticManager::AddDiagnostic(llvm::StringRef message, 121 lldb::Severity severity, 122 DiagnosticOrigin origin, 123 uint32_t compiler_id) { 124 m_diagnostics.emplace_back(std::make_unique<Diagnostic>( 125 origin, compiler_id, 126 DiagnosticDetail{{}, severity, message.str(), message.str()})); 127 } 128 129 size_t DiagnosticManager::Printf(lldb::Severity severity, const char *format, 130 ...) { 131 StreamString ss; 132 133 va_list args; 134 va_start(args, format); 135 size_t result = ss.PrintfVarArg(format, args); 136 va_end(args); 137 138 AddDiagnostic(ss.GetString(), severity, eDiagnosticOriginLLDB); 139 140 return result; 141 } 142 143 void DiagnosticManager::PutString(lldb::Severity severity, 144 llvm::StringRef str) { 145 if (str.empty()) 146 return; 147 AddDiagnostic(str, severity, eDiagnosticOriginLLDB); 148 } 149 150 void Diagnostic::AppendMessage(llvm::StringRef message, 151 bool precede_with_newline) { 152 if (precede_with_newline) { 153 m_detail.message.push_back('\n'); 154 m_detail.rendered.push_back('\n'); 155 } 156 m_detail.message += message; 157 m_detail.rendered += message; 158 } 159