xref: /llvm-project/lldb/source/Expression/DiagnosticManager.cpp (revision 089227feaf0efb5e540783a5542655e25669e7d8)
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