1 //===-- CommandReturnObject.cpp -------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Interpreter/CommandReturnObject.h"
11 #include "lldb/Utility/DiagnosticsRendering.h"
12 #include "lldb/Utility/Status.h"
13 #include "lldb/Utility/StreamString.h"
16 using namespace lldb_private
;
18 static llvm::raw_ostream
&error(Stream
&strm
) {
19 return llvm::WithColor(strm
.AsRawOstream(), llvm::HighlightColor::Error
,
20 llvm::ColorMode::Enable
)
24 static llvm::raw_ostream
&warning(Stream
&strm
) {
25 return llvm::WithColor(strm
.AsRawOstream(), llvm::HighlightColor::Warning
,
26 llvm::ColorMode::Enable
)
30 static llvm::raw_ostream
¬e(Stream
&strm
) {
31 return llvm::WithColor(strm
.AsRawOstream(), llvm::HighlightColor::Note
,
32 llvm::ColorMode::Enable
)
36 static void DumpStringToStreamWithNewline(Stream
&strm
, const std::string
&s
) {
37 bool add_newline
= false;
39 // We already checked for empty above, now make sure there is a newline in
40 // the error, and if there isn't one, add one.
41 strm
.Write(s
.c_str(), s
.size());
43 const char last_char
= *s
.rbegin();
44 add_newline
= last_char
!= '\n' && last_char
!= '\r';
50 CommandReturnObject::CommandReturnObject(bool colors
)
51 : m_out_stream(colors
), m_err_stream(colors
), m_colors(colors
) {}
53 void CommandReturnObject::AppendErrorWithFormat(const char *format
, ...) {
54 SetStatus(eReturnStatusFailed
);
59 va_start(args
, format
);
61 sstrm
.PrintfVarArg(format
, args
);
64 const std::string
&s
= std::string(sstrm
.GetString());
66 error(GetErrorStream());
67 DumpStringToStreamWithNewline(GetErrorStream(), s
);
71 void CommandReturnObject::AppendMessageWithFormat(const char *format
, ...) {
75 va_start(args
, format
);
77 sstrm
.PrintfVarArg(format
, args
);
80 GetOutputStream() << sstrm
.GetString();
83 void CommandReturnObject::AppendNoteWithFormat(const char *format
, ...) {
87 va_start(args
, format
);
89 sstrm
.PrintfVarArg(format
, args
);
92 note(GetOutputStream()) << sstrm
.GetString();
95 void CommandReturnObject::AppendWarningWithFormat(const char *format
, ...) {
99 va_start(args
, format
);
101 sstrm
.PrintfVarArg(format
, args
);
104 warning(GetErrorStream()) << sstrm
.GetString();
107 void CommandReturnObject::AppendMessage(llvm::StringRef in_string
) {
108 if (in_string
.empty())
110 GetOutputStream() << in_string
.rtrim() << '\n';
113 void CommandReturnObject::AppendNote(llvm::StringRef in_string
) {
114 if (in_string
.empty())
116 note(GetOutputStream()) << in_string
.rtrim() << '\n';
119 void CommandReturnObject::AppendWarning(llvm::StringRef in_string
) {
120 if (in_string
.empty())
122 warning(GetErrorStream()) << in_string
.rtrim() << '\n';
125 void CommandReturnObject::AppendError(llvm::StringRef in_string
) {
126 SetStatus(eReturnStatusFailed
);
127 if (in_string
.empty())
129 // Workaround to deal with already fully formatted compiler diagnostics.
130 llvm::StringRef
msg(in_string
.rtrim());
131 msg
.consume_front("error: ");
132 error(GetErrorStream()) << msg
<< '\n';
135 void CommandReturnObject::SetError(Status error
) {
136 SetError(error
.takeError());
139 void CommandReturnObject::SetError(llvm::Error error
) {
140 // Retrieve any diagnostics.
141 error
= llvm::handleErrors(std::move(error
), [&](DiagnosticError
&error
) {
142 SetStatus(eReturnStatusFailed
);
143 m_diagnostics
= error
.GetDetails();
146 AppendError(llvm::toString(std::move(error
)));
150 std::string
CommandReturnObject::GetInlineDiagnosticString(unsigned indent
) {
151 StreamString
diag_stream(m_colors
);
152 RenderDiagnosticDetails(diag_stream
, indent
, true, m_diagnostics
);
153 // Duplex the diagnostics to the secondary stream (but not inlined).
154 if (auto stream_sp
= m_err_stream
.GetStreamAtIndex(eImmediateStreamIndex
))
155 RenderDiagnosticDetails(*stream_sp
, std::nullopt
, false, m_diagnostics
);
157 return diag_stream
.GetString().str();
160 std::string
CommandReturnObject::GetErrorString(bool with_diagnostics
) {
161 StreamString
stream(m_colors
);
162 if (with_diagnostics
)
163 RenderDiagnosticDetails(stream
, std::nullopt
, false, m_diagnostics
);
165 lldb::StreamSP
stream_sp(m_err_stream
.GetStreamAtIndex(eStreamStringIndex
));
167 stream
<< std::static_pointer_cast
<StreamString
>(stream_sp
)->GetString();
168 return stream
.GetString().str();
171 StructuredData::ObjectSP
CommandReturnObject::GetErrorData() {
172 auto make_array
= []() { return std::make_unique
<StructuredData::Array
>(); };
173 auto make_bool
= [](bool b
) {
174 return std::make_unique
<StructuredData::Boolean
>(b
);
176 auto make_dict
= []() {
177 return std::make_unique
<StructuredData::Dictionary
>();
179 auto make_int
= [](unsigned i
) {
180 return std::make_unique
<StructuredData::UnsignedInteger
>(i
);
182 auto make_string
= [](llvm::StringRef s
) {
183 return std::make_unique
<StructuredData::String
>(s
);
185 auto dict_up
= make_dict();
186 dict_up
->AddItem("version", make_int(1));
187 auto array_up
= make_array();
188 for (const DiagnosticDetail
&diag
: m_diagnostics
) {
189 auto detail_up
= make_dict();
190 if (auto &sloc
= diag
.source_location
) {
191 auto sloc_up
= make_dict();
192 sloc_up
->AddItem("file", make_string(sloc
->file
.GetPath()));
193 sloc_up
->AddItem("line", make_int(sloc
->line
));
194 sloc_up
->AddItem("length", make_int(sloc
->length
));
195 sloc_up
->AddItem("hidden", make_bool(sloc
->hidden
));
196 sloc_up
->AddItem("in_user_input", make_bool(sloc
->in_user_input
));
197 detail_up
->AddItem("source_location", std::move(sloc_up
));
199 llvm::StringRef severity
= "unknown";
200 switch (diag
.severity
) {
201 case lldb::eSeverityError
:
204 case lldb::eSeverityWarning
:
205 severity
= "warning";
207 case lldb::eSeverityInfo
:
211 detail_up
->AddItem("severity", make_string(severity
));
212 detail_up
->AddItem("message", make_string(diag
.message
));
213 detail_up
->AddItem("rendered", make_string(diag
.rendered
));
214 array_up
->AddItem(std::move(detail_up
));
216 dict_up
->AddItem("details", std::move(array_up
));
217 if (auto stream_sp
= m_err_stream
.GetStreamAtIndex(eStreamStringIndex
)) {
218 auto text
= std::static_pointer_cast
<StreamString
>(stream_sp
)->GetString();
220 dict_up
->AddItem("text", make_string(text
));
225 // Similar to AppendError, but do not prepend 'Status: ' to message, and don't
226 // append "\n" to the end of it.
228 void CommandReturnObject::AppendRawError(llvm::StringRef in_string
) {
229 SetStatus(eReturnStatusFailed
);
230 assert(!in_string
.empty() && "Expected a non-empty error message");
231 GetErrorStream() << in_string
;
234 void CommandReturnObject::SetStatus(ReturnStatus status
) { m_status
= status
; }
236 ReturnStatus
CommandReturnObject::GetStatus() const { return m_status
; }
238 bool CommandReturnObject::Succeeded() const {
239 return m_status
<= eReturnStatusSuccessContinuingResult
;
242 bool CommandReturnObject::HasResult() const {
243 return (m_status
== eReturnStatusSuccessFinishResult
||
244 m_status
== eReturnStatusSuccessContinuingResult
);
247 void CommandReturnObject::Clear() {
248 lldb::StreamSP stream_sp
;
249 stream_sp
= m_out_stream
.GetStreamAtIndex(eStreamStringIndex
);
251 static_cast<StreamString
*>(stream_sp
.get())->Clear();
252 stream_sp
= m_err_stream
.GetStreamAtIndex(eStreamStringIndex
);
254 static_cast<StreamString
*>(stream_sp
.get())->Clear();
255 m_diagnostics
.clear();
256 m_status
= eReturnStatusStarted
;
257 m_did_change_process_state
= false;
258 m_suppress_immediate_output
= false;
259 m_interactive
= true;
262 bool CommandReturnObject::GetDidChangeProcessState() const {
263 return m_did_change_process_state
;
266 void CommandReturnObject::SetDidChangeProcessState(bool b
) {
267 m_did_change_process_state
= b
;
270 bool CommandReturnObject::GetInteractive() const { return m_interactive
; }
272 void CommandReturnObject::SetInteractive(bool b
) { m_interactive
= b
; }
274 bool CommandReturnObject::GetSuppressImmediateOutput() const {
275 return m_suppress_immediate_output
;
278 void CommandReturnObject::SetSuppressImmediateOutput(bool b
) {
279 m_suppress_immediate_output
= b
;