Skip to content

Cherry pick inline diagnostics #9426

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

Merged
Merged
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
14,247 changes: 5,134 additions & 9,113 deletions lldb/bindings/python/static-binding/LLDBWrapPython.cpp

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions lldb/bindings/python/static-binding/lldb.py
Original file line number Diff line number Diff line change
Expand Up @@ -3755,6 +3755,10 @@ def IsValid(self):
r"""IsValid(SBCommandReturnObject self) -> bool"""
return _lldb.SBCommandReturnObject_IsValid(self)

def GetErrorData(self):
r"""GetErrorData(SBCommandReturnObject self) -> SBStructuredData"""
return _lldb.SBCommandReturnObject_GetErrorData(self)

def PutOutput(self, *args):
r"""
PutOutput(SBCommandReturnObject self, SBFile file) -> size_t
Expand Down Expand Up @@ -4968,6 +4972,10 @@ def GetUseColor(self):
r"""GetUseColor(SBDebugger self) -> bool"""
return _lldb.SBDebugger_GetUseColor(self)

def SetShowInlineDiagnostics(self, arg2):
r"""SetShowInlineDiagnostics(SBDebugger self, bool arg2) -> bool"""
return _lldb.SBDebugger_SetShowInlineDiagnostics(self, arg2)

def SetUseSourceCache(self, use_source_cache):
r"""SetUseSourceCache(SBDebugger self, bool use_source_cache) -> bool"""
return _lldb.SBDebugger_SetUseSourceCache(self, use_source_cache)
Expand Down
1 change: 1 addition & 0 deletions lldb/include/lldb/API/SBCommandReturnObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class LLDB_API SBCommandReturnObject {
const char *GetOutput();

const char *GetError();
SBStructuredData GetErrorData();

#ifndef SWIG
LLDB_DEPRECATED_FIXME("Use PutOutput(SBFile) or PutOutput(FileSP)",
Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/API/SBDebugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,8 @@ class LLDB_API SBDebugger {

bool GetUseColor() const;

bool SetShowInlineDiagnostics(bool);

bool SetUseSourceCache(bool use_source_cache);

bool GetUseSourceCache() const;
Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/API/SBStructuredData.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLDB_API_SBSTRUCTUREDDATA_H
#define LLDB_API_SBSTRUCTUREDDATA_H

#include "lldb/API/SBCommandReturnObject.h"
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBModule.h"
#include "lldb/API/SBScriptObject.h"
Expand Down Expand Up @@ -110,6 +111,7 @@ class SBStructuredData {

protected:
friend class SBAttachInfo;
friend class SBCommandReturnObject;
friend class SBLaunchInfo;
friend class SBDebugger;
friend class SBFrame;
Expand Down
4 changes: 4 additions & 0 deletions lldb/include/lldb/Core/Debugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,10 @@ class Debugger : public std::enable_shared_from_this<Debugger>,

const std::string &GetInstanceName() { return m_instance_name; }

bool GetShowInlineDiagnostics() const;

bool SetShowInlineDiagnostics(bool);

bool LoadPlugin(const FileSpec &spec, Status &error);

void RunIOHandlers();
Expand Down
37 changes: 6 additions & 31 deletions lldb/include/lldb/Expression/DiagnosticManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "lldb/lldb-defines.h"
#include "lldb/lldb-types.h"

#include "lldb/Utility/DiagnosticsRendering.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Status.h"

Expand All @@ -23,48 +24,22 @@

namespace lldb_private {

/// A compiler-independent representation of a Diagnostic. Expression
/// evaluation failures often have more than one diagnostic that a UI
/// layer might want to render differently, for example to colorize
/// it.
///
/// Running example:
/// (lldb) expr 1+foo
/// error: <user expression 0>:1:3: use of undeclared identifier 'foo'
/// 1+foo
/// ^
struct DiagnosticDetail {
struct SourceLocation {
FileSpec file;
unsigned line = 0;
uint16_t column = 0;
uint16_t length = 0;
bool in_user_input = false;
};
/// Contains {{}, 1, 3, 3, true} in the example above.
std::optional<SourceLocation> source_location;
/// Contains eSeverityError in the example above.
lldb::Severity severity = lldb::eSeverityInfo;
/// Contains "use of undeclared identifier 'x'" in the example above.
std::string message;
/// Contains the fully rendered error message.
std::string rendered;
};

/// An llvm::Error used to communicate diagnostics in Status. Multiple
/// diagnostics may be chained in an llvm::ErrorList.
class ExpressionError
: public llvm::ErrorInfo<ExpressionError, ExpressionErrorBase> {
: public llvm::ErrorInfo<ExpressionError, DiagnosticError> {
std::string m_message;
std::vector<DiagnosticDetail> m_details;

public:
static char ID;
using llvm::ErrorInfo<ExpressionError, ExpressionErrorBase>::ErrorInfo;
using llvm::ErrorInfo<ExpressionError, DiagnosticError>::ErrorInfo;
ExpressionError(lldb::ExpressionResults result, std::string msg,
std::vector<DiagnosticDetail> details = {});
std::string message() const override;
llvm::ArrayRef<DiagnosticDetail> GetDetails() const { return m_details; }
llvm::ArrayRef<DiagnosticDetail> GetDetails() const override {
return m_details;
}
std::error_code convertToErrorCode() const override;
void log(llvm::raw_ostream &OS) const override;
std::unique_ptr<CloneableError> Clone() const override;
Expand Down
8 changes: 8 additions & 0 deletions lldb/include/lldb/Interpreter/CommandObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,13 @@ class CommandObject : public std::enable_shared_from_this<CommandObject> {
return false;
}

/// Set the command input as it appeared in the terminal. This
/// is used to have errors refer directly to the original command.
void SetOriginalCommandString(std::string s) { m_original_command = s; }

/// \param offset_in_command is on what column \c args_string
/// appears, if applicable. This enables diagnostics that refer back
/// to the user input.
virtual void Execute(const char *args_string,
CommandReturnObject &result) = 0;

Expand Down Expand Up @@ -404,6 +411,7 @@ class CommandObject : public std::enable_shared_from_this<CommandObject> {
std::string m_cmd_help_short;
std::string m_cmd_help_long;
std::string m_cmd_syntax;
std::string m_original_command;
Flags m_flags;
std::vector<CommandArgumentEntry> m_arguments;
lldb::CommandOverrideCallback m_deprecated_command_override_callback;
Expand Down
33 changes: 25 additions & 8 deletions lldb/include/lldb/Interpreter/CommandReturnObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
#define LLDB_INTERPRETER_COMMANDRETURNOBJECT_H

#include "lldb/Host/StreamFile.h"
#include "lldb/Utility/DiagnosticsRendering.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StreamTee.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private.h"

#include "llvm/ADT/StringRef.h"
Expand All @@ -29,19 +31,23 @@ class CommandReturnObject {

~CommandReturnObject() = default;

llvm::StringRef GetOutputData() {
/// Format any inline diagnostics with an indentation of \c indent.
std::string GetInlineDiagnosticString(unsigned indent);

llvm::StringRef GetOutputString() {
lldb::StreamSP stream_sp(m_out_stream.GetStreamAtIndex(eStreamStringIndex));
if (stream_sp)
return std::static_pointer_cast<StreamString>(stream_sp)->GetString();
return llvm::StringRef();
}

llvm::StringRef GetErrorData() {
lldb::StreamSP stream_sp(m_err_stream.GetStreamAtIndex(eStreamStringIndex));
if (stream_sp)
return std::static_pointer_cast<StreamString>(stream_sp)->GetString();
return llvm::StringRef();
}
/// Return the errors as a string.
///
/// If \c with_diagnostics is true, all diagnostics are also
/// rendered into the string. Otherwise the expectation is that they
/// are fetched with \ref GetInlineDiagnosticString().
std::string GetErrorString(bool with_diagnostics = true);
StructuredData::ObjectSP GetErrorData();

Stream &GetOutputStream() {
// Make sure we at least have our normal string stream output stream
Expand Down Expand Up @@ -131,10 +137,18 @@ class CommandReturnObject {
AppendError(llvm::formatv(format, std::forward<Args>(args)...).str());
}

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

void SetError(llvm::Error error);

void SetDiagnosticIndent(std::optional<uint16_t> indent) {
m_diagnostic_indent = indent;
}

std::optional<uint16_t> GetDiagnosticIndent() const {
return m_diagnostic_indent;
}

lldb::ReturnStatus GetStatus() const;

void SetStatus(lldb::ReturnStatus status);
Expand All @@ -160,6 +174,8 @@ class CommandReturnObject {

StreamTee m_out_stream;
StreamTee m_err_stream;
std::vector<DiagnosticDetail> m_diagnostics;
std::optional<uint16_t> m_diagnostic_indent;

lldb::ReturnStatus m_status = lldb::eReturnStatusStarted;

Expand All @@ -168,6 +184,7 @@ class CommandReturnObject {

/// If true, then the input handle from the debugger will be hooked up.
bool m_interactive = true;
bool m_colors;
};

} // namespace lldb_private
Expand Down
6 changes: 5 additions & 1 deletion lldb/include/lldb/Utility/Args.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,23 @@ class Args {

std::unique_ptr<char[]> ptr;
char quote = '\0';
/// The position of the argument in the original argument string.
std::optional<uint16_t> column;

char *data() { return ptr.get(); }

public:
ArgEntry() = default;
ArgEntry(llvm::StringRef str, char quote);
ArgEntry(llvm::StringRef str, char quote, std::optional<uint16_t> column);

llvm::StringRef ref() const { return c_str(); }
const char *c_str() const { return ptr.get(); }

/// Returns true if this argument was quoted in any way.
bool IsQuoted() const { return quote != '\0'; }
char GetQuoteChar() const { return quote; }
std::optional<uint16_t> GetPos() const { return column; }
size_t GetLength() const { return ref().size(); }
};

/// Construct with an option command string.
Expand Down
75 changes: 75 additions & 0 deletions lldb/include/lldb/Utility/DiagnosticsRendering.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//===-- DiagnosticsRendering.h ----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_UTILITY_DIAGNOSTICSRENDERING_H
#define LLDB_UTILITY_DIAGNOSTICSRENDERING_H

#include "lldb/Utility/Status.h"
#include "lldb/Utility/Stream.h"
#include "llvm/Support/WithColor.h"

namespace lldb_private {

/// A compiler-independent representation of an \c
/// lldb_private::Diagnostic. Expression evaluation failures often
/// have more than one diagnostic that a UI layer might want to render
/// differently, for example to colorize it.
///
/// Running example:
/// (lldb) expr 1 + foo
/// error: <user expression 0>:1:3: use of undeclared identifier 'foo'
/// 1 + foo
/// ^~~
struct DiagnosticDetail {
/// A source location consisting of a file name and position.
struct SourceLocation {
/// \c "<user expression 0>" in the example above.
FileSpec file;
/// \c 1 in the example above.
unsigned line = 0;
/// \c 5 in the example above.
uint16_t column = 0;
/// \c 3 in the example above.
uint16_t length = 0;
/// Whether this source location should be surfaced to the
/// user. For example, syntax errors diagnosed in LLDB's
/// expression wrapper code have this set to true.
bool hidden = false;
/// Whether this source location refers to something the user
/// typed as part of the command, i.e., if this qualifies for
/// inline display, or if the source line would need to be echoed
/// again for the message to make sense.
bool in_user_input = false;
};
/// Contains this diagnostic's source location, if applicable.
std::optional<SourceLocation> source_location;
/// Contains \c eSeverityError in the example above.
lldb::Severity severity = lldb::eSeverityInfo;
/// Contains "use of undeclared identifier 'foo'" in the example above.
std::string message;
/// Contains the fully rendered error message, without "error: ",
/// but including the source context.
std::string rendered;
};

class DiagnosticError
: public llvm::ErrorInfo<DiagnosticError, CloneableECError> {
public:
using llvm::ErrorInfo<DiagnosticError, CloneableECError>::ErrorInfo;
DiagnosticError(std::error_code ec) : ErrorInfo(ec) {}
lldb::ErrorType GetErrorType() const override;
virtual llvm::ArrayRef<DiagnosticDetail> GetDetails() const = 0;
static char ID;
};

void RenderDiagnosticDetails(Stream &stream,
std::optional<uint16_t> offset_in_command,
bool show_inline,
llvm::ArrayRef<DiagnosticDetail> details);
} // namespace lldb_private
#endif
13 changes: 1 addition & 12 deletions 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/Utility/FileSpec.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-enumerations.h"
#include "llvm/ADT/StringRef.h"
Expand All @@ -26,8 +27,6 @@ class raw_ostream;

namespace lldb_private {

const char *ExpressionResultAsCString(lldb::ExpressionResults result);

/// Going a bit against the spirit of llvm::Error,
/// lldb_private::Status need to store errors long-term and sometimes
/// copy them. This base class defines an interface for this
Expand Down Expand Up @@ -79,16 +78,6 @@ class Win32Error : public llvm::ErrorInfo<Win32Error, CloneableECError> {
static char ID;
};

class ExpressionErrorBase
: public llvm::ErrorInfo<ExpressionErrorBase, CloneableECError> {
public:
using llvm::ErrorInfo<ExpressionErrorBase, CloneableECError>::ErrorInfo;
ExpressionErrorBase(std::error_code ec, std::string msg = {})
: ErrorInfo(ec) {}
lldb::ErrorType GetErrorType() const override;
static char ID;
};

/// \class Status Status.h "lldb/Utility/Status.h" An error handling class.
///
/// This class is designed to be able to hold any error code that can be
Expand Down
Loading