232 lines · cpp
1//===-- CommandReturnObject.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Interpreter/CommandReturnObject.h"10 11#include "lldb/Host/common/DiagnosticsRendering.h"12#include "lldb/Utility/Status.h"13#include "lldb/Utility/StreamString.h"14 15using namespace lldb;16using namespace lldb_private;17 18static llvm::raw_ostream &error(Stream &strm) {19 return llvm::WithColor(strm.AsRawOstream(), llvm::HighlightColor::Error,20 llvm::ColorMode::Enable)21 << "error: ";22}23 24static llvm::raw_ostream &warning(Stream &strm) {25 return llvm::WithColor(strm.AsRawOstream(), llvm::HighlightColor::Warning,26 llvm::ColorMode::Enable)27 << "warning: ";28}29 30static llvm::raw_ostream ¬e(Stream &strm) {31 return llvm::WithColor(strm.AsRawOstream(), llvm::HighlightColor::Note,32 llvm::ColorMode::Enable)33 << "note: ";34}35 36static void DumpStringToStreamWithNewline(Stream &strm, const std::string &s) {37 bool add_newline = false;38 if (!s.empty()) {39 // We already checked for empty above, now make sure there is a newline in40 // the error, and if there isn't one, add one.41 strm.Write(s.c_str(), s.size());42 43 const char last_char = *s.rbegin();44 add_newline = last_char != '\n' && last_char != '\r';45 }46 if (add_newline)47 strm.EOL();48}49 50CommandReturnObject::CommandReturnObject(bool colors)51 : m_out_stream(colors), m_err_stream(colors), m_colors(colors) {}52 53void CommandReturnObject::AppendErrorWithFormat(const char *format, ...) {54 SetStatus(eReturnStatusFailed);55 56 if (!format)57 return;58 va_list args;59 va_start(args, format);60 StreamString sstrm;61 sstrm.PrintfVarArg(format, args);62 va_end(args);63 64 const std::string &s = std::string(sstrm.GetString());65 if (!s.empty()) {66 error(GetErrorStream());67 DumpStringToStreamWithNewline(GetErrorStream(), s);68 }69}70 71void CommandReturnObject::AppendMessageWithFormat(const char *format, ...) {72 if (!format)73 return;74 va_list args;75 va_start(args, format);76 StreamString sstrm;77 sstrm.PrintfVarArg(format, args);78 va_end(args);79 80 GetOutputStream() << sstrm.GetString();81}82 83void CommandReturnObject::AppendNoteWithFormat(const char *format, ...) {84 if (!format)85 return;86 va_list args;87 va_start(args, format);88 StreamString sstrm;89 sstrm.PrintfVarArg(format, args);90 va_end(args);91 92 note(GetOutputStream()) << sstrm.GetString();93}94 95void CommandReturnObject::AppendWarningWithFormat(const char *format, ...) {96 if (!format)97 return;98 va_list args;99 va_start(args, format);100 StreamString sstrm;101 sstrm.PrintfVarArg(format, args);102 va_end(args);103 104 warning(GetErrorStream()) << sstrm.GetString();105}106 107void CommandReturnObject::AppendMessage(llvm::StringRef in_string) {108 if (in_string.empty())109 return;110 GetOutputStream() << in_string.rtrim() << '\n';111}112 113void CommandReturnObject::AppendNote(llvm::StringRef in_string) {114 if (in_string.empty())115 return;116 note(GetOutputStream()) << in_string.rtrim() << '\n';117}118 119void CommandReturnObject::AppendWarning(llvm::StringRef in_string) {120 if (in_string.empty())121 return;122 warning(GetErrorStream()) << in_string.rtrim() << '\n';123}124 125void CommandReturnObject::AppendError(llvm::StringRef in_string) {126 SetStatus(eReturnStatusFailed);127 if (in_string.empty())128 return;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';133}134 135void CommandReturnObject::SetError(Status error) {136 SetError(error.takeError());137}138 139void 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();144 });145 if (error) {146 AppendError(llvm::toString(std::move(error)));147 }148}149 150std::string151CommandReturnObject::GetInlineDiagnosticString(unsigned indent) const {152 StreamString diag_stream(m_colors);153 RenderDiagnosticDetails(diag_stream, indent, true, m_diagnostics);154 // Duplex the diagnostics to the secondary stream (but not inlined).155 if (auto stream_sp = m_err_stream.GetStreamAtIndex(eImmediateStreamIndex))156 RenderDiagnosticDetails(*stream_sp, std::nullopt, false, m_diagnostics);157 158 return diag_stream.GetString().str();159}160 161std::string CommandReturnObject::GetErrorString(bool with_diagnostics) const {162 StreamString stream(m_colors);163 if (with_diagnostics)164 RenderDiagnosticDetails(stream, std::nullopt, false, m_diagnostics);165 166 lldb::StreamSP stream_sp(m_err_stream.GetStreamAtIndex(eStreamStringIndex));167 if (stream_sp)168 stream << std::static_pointer_cast<StreamString>(stream_sp)->GetString();169 return stream.GetString().str();170}171 172StructuredData::ObjectSP CommandReturnObject::GetErrorData() {173 return Serialize(m_diagnostics);174}175 176// Similar to AppendError, but do not prepend 'Status: ' to message, and don't177// append "\n" to the end of it.178 179void CommandReturnObject::AppendRawError(llvm::StringRef in_string) {180 SetStatus(eReturnStatusFailed);181 assert(!in_string.empty() && "Expected a non-empty error message");182 GetErrorStream() << in_string;183}184 185void CommandReturnObject::SetStatus(ReturnStatus status) { m_status = status; }186 187ReturnStatus CommandReturnObject::GetStatus() const { return m_status; }188 189bool CommandReturnObject::Succeeded() const {190 return m_status <= eReturnStatusSuccessContinuingResult;191}192 193bool CommandReturnObject::HasResult() const {194 return (m_status == eReturnStatusSuccessFinishResult ||195 m_status == eReturnStatusSuccessContinuingResult);196}197 198void CommandReturnObject::Clear() {199 lldb::StreamSP stream_sp;200 stream_sp = m_out_stream.GetStreamAtIndex(eStreamStringIndex);201 if (stream_sp)202 static_cast<StreamString *>(stream_sp.get())->Clear();203 stream_sp = m_err_stream.GetStreamAtIndex(eStreamStringIndex);204 if (stream_sp)205 static_cast<StreamString *>(stream_sp.get())->Clear();206 m_diagnostics.clear();207 m_status = eReturnStatusStarted;208 m_did_change_process_state = false;209 m_suppress_immediate_output = false;210 m_interactive = true;211}212 213bool CommandReturnObject::GetDidChangeProcessState() const {214 return m_did_change_process_state;215}216 217void CommandReturnObject::SetDidChangeProcessState(bool b) {218 m_did_change_process_state = b;219}220 221bool CommandReturnObject::GetInteractive() const { return m_interactive; }222 223void CommandReturnObject::SetInteractive(bool b) { m_interactive = b; }224 225bool CommandReturnObject::GetSuppressImmediateOutput() const {226 return m_suppress_immediate_output;227}228 229void CommandReturnObject::SetSuppressImmediateOutput(bool b) {230 m_suppress_immediate_output = b;231}232