blob: 5fdd090253a8270af2e611bb96b9f972c80f88bb [file] [log] [blame] [edit]
//===-- DiagnosticRendering.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_SOURCE_COMMANDS_DIAGNOSTICRENDERING_H
#define LLDB_SOURCE_COMMANDS_DIAGNOSTICRENDERING_H
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Utility/Stream.h"
#include "llvm/Support/WithColor.h"
namespace lldb_private {
static llvm::raw_ostream &PrintSeverity(Stream &stream,
lldb::Severity severity) {
llvm::HighlightColor color;
llvm::StringRef text;
switch (severity) {
case lldb::eSeverityError:
color = llvm::HighlightColor::Error;
text = "error: ";
break;
case lldb::eSeverityWarning:
color = llvm::HighlightColor::Warning;
text = "warning: ";
break;
case lldb::eSeverityInfo:
color = llvm::HighlightColor::Remark;
text = "note: ";
break;
}
return llvm::WithColor(stream.AsRawOstream(), color, llvm::ColorMode::Enable)
<< text;
}
// Public for unittesting.
static void RenderDiagnosticDetails(Stream &stream,
std::optional<uint16_t> offset_in_command,
bool show_inline,
llvm::ArrayRef<DiagnosticDetail> details) {
if (details.empty())
return;
if (!offset_in_command) {
for (const DiagnosticDetail &detail : details) {
PrintSeverity(stream, detail.severity);
stream << detail.rendered << '\n';
}
return;
}
// Print a line with caret indicator(s) below the lldb prompt + command.
const size_t padding = *offset_in_command;
stream << std::string(padding, ' ');
size_t offset = 1;
std::vector<DiagnosticDetail> remaining_details, other_details,
hidden_details;
for (const DiagnosticDetail &detail : details) {
if (!show_inline || !detail.source_location) {
other_details.push_back(detail);
continue;
}
if (detail.source_location->hidden) {
hidden_details.push_back(detail);
continue;
}
if (!detail.source_location->in_user_input) {
other_details.push_back(detail);
continue;
}
auto &loc = *detail.source_location;
remaining_details.push_back(detail);
if (offset > loc.column)
continue;
stream << std::string(loc.column - offset, ' ') << '^';
if (loc.length > 1)
stream << std::string(loc.length - 1, '~');
offset = loc.column + 1;
}
stream << '\n';
// Work through each detail in reverse order using the vector/stack.
bool did_print = false;
for (auto detail = remaining_details.rbegin();
detail != remaining_details.rend();
++detail, remaining_details.pop_back()) {
// Get the information to print this detail and remove it from the stack.
// Print all the lines for all the other messages first.
stream << std::string(padding, ' ');
size_t offset = 1;
for (auto &remaining_detail :
llvm::ArrayRef(remaining_details).drop_back(1)) {
uint16_t column = remaining_detail.source_location->column;
stream << std::string(column - offset, ' ') << "│";
offset = column + 1;
}
// Print the line connecting the ^ with the error message.
uint16_t column = detail->source_location->column;
if (offset <= column)
stream << std::string(column - offset, ' ') << "╰─ ";
// Print a colorized string based on the message's severity type.
PrintSeverity(stream, detail->severity);
// Finally, print the message and start a new line.
stream << detail->message << '\n';
did_print = true;
}
// Print the non-located details.
for (const DiagnosticDetail &detail : other_details) {
PrintSeverity(stream, detail.severity);
stream << detail.rendered << '\n';
did_print = true;
}
// Print the hidden details as a last resort.
if (!did_print)
for (const DiagnosticDetail &detail : hidden_details) {
PrintSeverity(stream, detail.severity);
stream << detail.rendered << '\n';
}
}
} // namespace lldb_private
#endif