Skip to content

[lldb] DRAFT - Print multiple messages with line art that goes from each indicator #80938

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 1 addition & 14 deletions lldb/include/lldb/Expression/DiagnosticManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLDB_EXPRESSION_DIAGNOSTICMANAGER_H

#include "lldb/lldb-defines.h"
#include "lldb/lldb-private-enumerations.h"
#include "lldb/lldb-types.h"

#include "llvm/ADT/STLExtras.h"
Expand All @@ -20,20 +21,6 @@

namespace lldb_private {

enum DiagnosticOrigin {
eDiagnosticOriginUnknown = 0,
eDiagnosticOriginLLDB,
eDiagnosticOriginClang,
eDiagnosticOriginSwift,
eDiagnosticOriginLLVM
};

enum DiagnosticSeverity {
eDiagnosticSeverityError,
eDiagnosticSeverityWarning,
eDiagnosticSeverityRemark
};

const uint32_t LLDB_INVALID_COMPILER_ID = UINT32_MAX;

class Diagnostic {
Expand Down
4 changes: 4 additions & 0 deletions lldb/include/lldb/Interpreter/CommandReturnObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ class CommandReturnObject {

void SetError(const Status &error, const char *fallback_error_cstr = nullptr);

std::string DetailStringForPromptCommand(size_t prompt_size,
llvm::StringRef input);

void SetError(llvm::Error error);

lldb::ReturnStatus GetStatus() const;
Expand Down Expand Up @@ -162,6 +165,7 @@ class CommandReturnObject {
StreamTee m_err_stream;

lldb::ReturnStatus m_status = lldb::eReturnStatusStarted;
Status m_error_status;

bool m_did_change_process_state = false;
bool m_suppress_immediate_output = false;
Expand Down
46 changes: 45 additions & 1 deletion lldb/include/lldb/Utility/Status.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLDB_UTILITY_STATUS_H
#define LLDB_UTILITY_STATUS_H

#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-enumerations.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -114,7 +115,7 @@ class Status {
/// The error type enumeration value.
lldb::ErrorType GetType() const;

void SetExpressionError(lldb::ExpressionResults, const char *mssg);
void SetExpressionError(lldb::ExpressionResults, const char *mssg = nullptr);

int SetExpressionErrorWithFormat(lldb::ExpressionResults, const char *format,
...) __attribute__((format(printf, 3, 4)));
Expand Down Expand Up @@ -180,19 +181,62 @@ class Status {
/// success (non-erro), \b false otherwise.
bool Success() const;

struct Detail;
void AddDetail(Status::Detail detail);
void SetErrorDetails(DiagnosticManager &diagnostic_manager);
std::vector<Status::Detail> GetDetails() const;

protected:
/// Member variables
ValueType m_code = 0; ///< Status code as an integer value.
lldb::ErrorType m_type =
lldb::eErrorTypeInvalid; ///< The type of the above error code.
mutable std::string m_string; ///< A string representation of the error code.
std::vector<Status::Detail> m_status_details;
mutable std::string m_string_with_details;

private:
explicit Status(const llvm::formatv_object_base &payload) {
SetErrorToGenericError();
m_string = payload.str();
}
};

struct Status::Detail {
private:
std::vector<std::string> m_message_lines;
DiagnosticSeverity m_message_type;
DiagnosticOrigin m_message_origin;

mutable std::optional<std::string> m_message;

static std::string StringForSeverity(DiagnosticSeverity severity);

std::vector<std::string>
GetMessageLinesFromDiagnostic(Diagnostic *diagnostic);

public:
Detail(const std::unique_ptr<Diagnostic> &diagnostic)
: m_message_lines(GetMessageLinesFromDiagnostic(diagnostic.get())),
m_message_type(diagnostic->GetSeverity()),
m_message_origin(diagnostic->getKind()) {}

Detail(const Detail &other)
: m_message_lines(other.m_message_lines),
m_message_type(other.m_message_type),
m_message_origin(other.m_message_origin) {}

Detail &operator=(const Detail &rhs) {
m_message_lines = rhs.m_message_lines;
m_message_type = rhs.m_message_type;
m_message_origin = rhs.m_message_origin;
return *this;
}

std::string GetMessage() const;
std::vector<std::string> GetMessageLines() const;
DiagnosticSeverity GetType() const { return m_message_type; }
};
} // namespace lldb_private

namespace llvm {
Expand Down
14 changes: 14 additions & 0 deletions lldb/include/lldb/lldb-private-enumerations.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,20 @@ enum LoadDependentFiles {
eLoadDependentsNo,
};

enum DiagnosticOrigin {
eDiagnosticOriginUnknown = 0,
eDiagnosticOriginLLDB,
eDiagnosticOriginClang,
eDiagnosticOriginSwift,
eDiagnosticOriginLLVM
};

enum DiagnosticSeverity {
eDiagnosticSeverityError,
eDiagnosticSeverityWarning,
eDiagnosticSeverityRemark
};

inline std::string GetStatDescription(lldb_private::StatisticKind K) {
switch (K) {
case StatisticKind::ExpressionSuccessful:
Expand Down
27 changes: 14 additions & 13 deletions lldb/source/Breakpoint/BreakpointLocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,6 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,

error.Clear();

DiagnosticManager diagnostics;

if (condition_hash != m_condition_hash || !m_user_expression_sp ||
!m_user_expression_sp->IsParseCacheable() ||
!m_user_expression_sp->MatchesContext(exe_ctx)) {
Expand All @@ -269,12 +267,14 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
return true;
}

if (!m_user_expression_sp->Parse(diagnostics, exe_ctx,
eExecutionPolicyOnlyWhenNeeded, true,
false)) {
error.SetErrorStringWithFormat(
"Couldn't parse conditional expression:\n%s",
diagnostics.GetString().c_str());
DiagnosticManager diagnostic_manager;

bool success = m_user_expression_sp->Parse(diagnostic_manager, exe_ctx,
eExecutionPolicyOnlyWhenNeeded,
true, false);
if (!success) {
error.SetErrorString("Couldn't parse conditional expression:");
error.SetErrorDetails(diagnostic_manager);
m_user_expression_sp.reset();
return true;
}
Expand All @@ -296,12 +296,13 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,

Status expr_error;

diagnostics.Clear();
DiagnosticManager diagnostic_manager;

ExpressionVariableSP result_variable_sp;

ExpressionResults result_code = m_user_expression_sp->Execute(
diagnostics, exe_ctx, options, m_user_expression_sp, result_variable_sp);
ExpressionResults result_code =
m_user_expression_sp->Execute(diagnostic_manager, exe_ctx, options,
m_user_expression_sp, result_variable_sp);

bool ret;

Expand Down Expand Up @@ -331,8 +332,8 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
}
} else {
ret = false;
error.SetErrorStringWithFormat("Couldn't execute expression:\n%s",
diagnostics.GetString().c_str());
error.SetErrorStringWithFormat("Couldn't execute expression:");
error.SetErrorDetails(diagnostic_manager);
}

return ret;
Expand Down
24 changes: 12 additions & 12 deletions lldb/source/Expression/UserExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,17 +325,16 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx,

if (!parse_success) {
std::string msg;
{
llvm::raw_string_ostream os(msg);
if (!diagnostic_manager.Diagnostics().empty())
os << diagnostic_manager.GetString();
else
os << "expression failed to parse (no further compiler diagnostics)";
if (target->GetEnableNotifyAboutFixIts() && fixed_expression &&
!fixed_expression->empty())
os << "\nfixed expression suggested:\n " << *fixed_expression;
if (diagnostic_manager.Diagnostics().empty())
msg += "expression failed to parse (no further compiler diagnostics)";

if (target->GetEnableNotifyAboutFixIts() && fixed_expression &&
!fixed_expression->empty()) {
msg += "\nfixed expression suggested:\n ";
msg += *fixed_expression;
}
error.SetExpressionError(execution_results, msg.c_str());
error.SetErrorDetails(diagnostic_manager);
}
}

Expand Down Expand Up @@ -378,9 +377,10 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx,
if (!diagnostic_manager.Diagnostics().size())
error.SetExpressionError(
execution_results, "expression failed to execute, unknown error");
else
error.SetExpressionError(execution_results,
diagnostic_manager.GetString().c_str());
else {
error.SetExpressionError(execution_results);
error.SetErrorDetails(diagnostic_manager);
}
} else {
if (expr_result) {
result_valobj_sp = expr_result->GetValueObject();
Expand Down
20 changes: 10 additions & 10 deletions lldb/source/Expression/UtilityFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,25 +87,25 @@ FunctionCaller *UtilityFunction::MakeFunctionCaller(
return nullptr;
}
if (m_caller_up) {
DiagnosticManager diagnostics;
DiagnosticManager diagnostic_manager;

unsigned num_errors =
m_caller_up->CompileFunction(thread_to_use_sp, diagnostics);
m_caller_up->CompileFunction(thread_to_use_sp, diagnostic_manager);
if (num_errors) {
error.SetErrorStringWithFormat(
"Error compiling %s caller function: \"%s\".",
m_function_name.c_str(), diagnostics.GetString().c_str());
error.SetErrorStringWithFormat("Error compiling %s caller function:",
m_function_name.c_str());
error.SetErrorDetails(diagnostic_manager);
m_caller_up.reset();
return nullptr;
}

diagnostics.Clear();
diagnostic_manager.Clear();
ExecutionContext exe_ctx(process_sp);

if (!m_caller_up->WriteFunctionWrapper(exe_ctx, diagnostics)) {
error.SetErrorStringWithFormat(
"Error inserting caller function for %s: \"%s\".",
m_function_name.c_str(), diagnostics.GetString().c_str());
if (!m_caller_up->WriteFunctionWrapper(exe_ctx, diagnostic_manager)) {
error.SetErrorStringWithFormat("Error inserting caller function for %s:",
m_function_name.c_str());
error.SetErrorDetails(diagnostic_manager);
m_caller_up.reset();
return nullptr;
}
Expand Down
22 changes: 20 additions & 2 deletions lldb/source/Interpreter/CommandInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3131,8 +3131,26 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,

// Now emit the command error text from the command we just executed
if (!result.GetImmediateErrorStream()) {
llvm::StringRef error = result.GetErrorData();
PrintCommandOutput(io_handler, error, false);
auto prompt_size = GetDebugger().GetPrompt().size();
auto command = line.empty() ? m_repeat_command : line;
auto detail_string =
result.DetailStringForPromptCommand(prompt_size, command);
if (detail_string.empty()) {
llvm::StringRef error = result.GetErrorData();
PrintCommandOutput(io_handler, error, false);
} else {
// Check whether the developer just hit [Return] to repeat a command.
if (line.empty()) {
// Build a recreation of the prompt and the last command.
std::string prompt_and_command(GetDebugger().GetPrompt());
prompt_and_command += m_repeat_command;

// Print the last command the developer entered for the caret line.
PrintCommandOutput(io_handler, prompt_and_command, false);
}

PrintCommandOutput(io_handler, detail_string, false);
}
}
}

Expand Down
Loading