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 {
name() const22 const char *name() const noexcept override {
23 return "LLDBExpressionCategory";
24 }
message(int __ev) const25 std::string message(int __ev) const override {
26 return toString(static_cast<lldb::ExpressionResults>(__ev));
27 };
28 };
expression_category()29 ExpressionCategory &expression_category() {
30 static ExpressionCategory g_expression_category;
31 return g_expression_category;
32 }
33
ExpressionError(lldb::ExpressionResults result,std::string msg,std::vector<DiagnosticDetail> details)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
StringForSeverity(lldb::Severity severity)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
message() const53 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
convertToErrorCode() const65 std::error_code ExpressionError::convertToErrorCode() const {
66 return llvm::inconvertibleErrorCode();
67 }
68
log(llvm::raw_ostream & OS) const69 void ExpressionError::log(llvm::raw_ostream &OS) const { OS << message(); }
70
Clone() const71 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
GetString(char separator)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 auto severity_pos = message.find(severity);
87 stream << message.take_front(severity_pos);
88
89 if (severity_pos != llvm::StringRef::npos)
90 stream << message.drop_front(severity_pos + severity.size());
91 stream << separator;
92 }
93 return str;
94 }
95
Dump(Log * log)96 void DiagnosticManager::Dump(Log *log) {
97 if (!log)
98 return;
99
100 std::string str = GetString();
101
102 // We want to remove the last '\n' because log->PutCString will add
103 // one for us.
104
105 if (!str.empty() && str.back() == '\n')
106 str.pop_back();
107
108 log->PutString(str);
109 }
110
GetAsError(lldb::ExpressionResults result,llvm::Twine message) const111 llvm::Error DiagnosticManager::GetAsError(lldb::ExpressionResults result,
112 llvm::Twine message) const {
113 std::vector<DiagnosticDetail> details;
114 for (const auto &diag : m_diagnostics)
115 details.push_back(diag->GetDetail());
116 return llvm::make_error<ExpressionError>(result, message.str(), details);
117 }
118
AddDiagnostic(llvm::StringRef message,lldb::Severity severity,DiagnosticOrigin origin,uint32_t compiler_id)119 void DiagnosticManager::AddDiagnostic(llvm::StringRef message,
120 lldb::Severity severity,
121 DiagnosticOrigin origin,
122 uint32_t compiler_id) {
123 m_diagnostics.emplace_back(std::make_unique<Diagnostic>(
124 origin, compiler_id,
125 DiagnosticDetail{{}, severity, message.str(), message.str()}));
126 }
127
Printf(lldb::Severity severity,const char * format,...)128 size_t DiagnosticManager::Printf(lldb::Severity severity, const char *format,
129 ...) {
130 StreamString ss;
131
132 va_list args;
133 va_start(args, format);
134 size_t result = ss.PrintfVarArg(format, args);
135 va_end(args);
136
137 AddDiagnostic(ss.GetString(), severity, eDiagnosticOriginLLDB);
138
139 return result;
140 }
141
PutString(lldb::Severity severity,llvm::StringRef str)142 void DiagnosticManager::PutString(lldb::Severity severity,
143 llvm::StringRef str) {
144 if (str.empty())
145 return;
146 AddDiagnostic(str, severity, eDiagnosticOriginLLDB);
147 }
148
AppendMessage(llvm::StringRef message,bool precede_with_newline)149 void Diagnostic::AppendMessage(llvm::StringRef message,
150 bool precede_with_newline) {
151 if (precede_with_newline) {
152 m_detail.message.push_back('\n');
153 m_detail.rendered.push_back('\n');
154 }
155 m_detail.message += message;
156 m_detail.rendered += message;
157 }
158