brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.4 KiB · f2cd396 Raw
236 lines · cpp
1//===-- DiagnosticsRendering.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/Host/common/DiagnosticsRendering.h"10#include <cstdint>11 12using namespace lldb_private;13using namespace lldb;14 15namespace lldb_private {16 17char DiagnosticError::ID;18 19lldb::ErrorType DiagnosticError::GetErrorType() const {20  return lldb::eErrorTypeExpression;21}22 23StructuredData::ObjectSP Serialize(llvm::ArrayRef<DiagnosticDetail> details) {24  auto make_array = []() { return std::make_unique<StructuredData::Array>(); };25  auto make_dict = []() {26    return std::make_unique<StructuredData::Dictionary>();27  };28  auto dict_up = make_dict();29  dict_up->AddIntegerItem("version", 1u);30  auto array_up = make_array();31  for (const DiagnosticDetail &diag : details) {32    auto detail_up = make_dict();33    if (auto &sloc = diag.source_location) {34      auto sloc_up = make_dict();35      sloc_up->AddStringItem("file", sloc->file.GetPath());36      sloc_up->AddIntegerItem("line", sloc->line);37      sloc_up->AddIntegerItem("length", sloc->length);38      sloc_up->AddBooleanItem("hidden", sloc->hidden);39      sloc_up->AddBooleanItem("in_user_input", sloc->in_user_input);40      detail_up->AddItem("source_location", std::move(sloc_up));41    }42    llvm::StringRef severity = "unknown";43    switch (diag.severity) {44    case lldb::eSeverityError:45      severity = "error";46      break;47    case lldb::eSeverityWarning:48      severity = "warning";49      break;50    case lldb::eSeverityInfo:51      severity = "note";52      break;53    }54    detail_up->AddStringItem("severity", severity);55    detail_up->AddStringItem("message", diag.message);56    detail_up->AddStringItem("rendered", diag.rendered);57    array_up->AddItem(std::move(detail_up));58  }59  dict_up->AddItem("details", std::move(array_up));60  return dict_up;61}62 63static llvm::raw_ostream &PrintSeverity(Stream &stream,64                                        lldb::Severity severity) {65  llvm::HighlightColor color;66  llvm::StringRef text;67  switch (severity) {68  case lldb::eSeverityError:69    color = llvm::HighlightColor::Error;70    text = "error: ";71    break;72  case lldb::eSeverityWarning:73    color = llvm::HighlightColor::Warning;74    text = "warning: ";75    break;76  case lldb::eSeverityInfo:77    color = llvm::HighlightColor::Remark;78    text = "note: ";79    break;80  }81  return llvm::WithColor(stream.AsRawOstream(), color, llvm::ColorMode::Enable)82         << text;83}84 85void RenderDiagnosticDetails(Stream &stream,86                             std::optional<uint16_t> offset_in_command,87                             bool show_inline,88                             llvm::ArrayRef<DiagnosticDetail> details) {89  if (details.empty())90    return;91 92  if (!offset_in_command) {93    for (const DiagnosticDetail &detail : details) {94      PrintSeverity(stream, detail.severity);95      stream << detail.rendered << '\n';96    }97    return;98  }99 100  // Since there is no other way to find this out, use the color101  // attribute as a proxy for whether the terminal supports Unicode102  // characters.  In the future it might make sense to move this into103  // Host so it can be customized for a specific platform.104  llvm::StringRef cursor, underline, vbar, joint, hbar, spacer;105  if (stream.AsRawOstream().colors_enabled()) {106    cursor = "˄";107    underline = "˜";108    vbar = "│";109    joint = "╰";110    hbar = "─";111    spacer = " ";112  } else {113    cursor = "^";114    underline = "~";115    vbar = "|";116    joint = "";117    hbar = "";118    spacer = "";119  }120 121  // Partition the diagnostics.122  std::vector<DiagnosticDetail> remaining_details, other_details,123      hidden_details;124  for (const DiagnosticDetail &detail : details) {125    if (!show_inline || !detail.source_location) {126      other_details.push_back(detail);127      continue;128    }129    if (detail.source_location->hidden) {130      hidden_details.push_back(detail);131      continue;132    }133    if (!detail.source_location->in_user_input) {134      other_details.push_back(detail);135      continue;136    }137 138    remaining_details.push_back(detail);139  }140 141  // Sort the diagnostics.142  auto sort = [](std::vector<DiagnosticDetail> &ds) {143    llvm::stable_sort(ds, [](auto &d1, auto &d2) {144      auto l1 = d1.source_location.value_or(DiagnosticDetail::SourceLocation{});145      auto l2 = d2.source_location.value_or(DiagnosticDetail::SourceLocation{});146      return std::tie(l1.line, l1.column) < std::tie(l2.line, l2.column);147    });148  };149  sort(remaining_details);150  sort(other_details);151  sort(hidden_details);152 153  // Print a line with caret indicator(s) below the lldb prompt + command.154  const size_t padding = *offset_in_command;155  stream << std::string(padding, ' ');156  {157    size_t x_pos = 1;158    for (const DiagnosticDetail &detail : remaining_details) {159      auto &loc = *detail.source_location;160 161      if (x_pos > loc.column)162        continue;163 164      stream << std::string(loc.column - x_pos, ' ') << cursor;165      x_pos = loc.column + 1;166      for (unsigned i = 0; i + 1 < loc.length; ++i) {167        stream << underline;168        x_pos += 1;169      }170    }171  }172  stream << '\n';173 174  // Reverse the order within groups of diagnostics that are on the same column.175  auto group = [](std::vector<DiagnosticDetail> &details) {176    for (auto it = details.begin(), end = details.end(); it != end;) {177      auto eq_end = std::find_if(it, end, [&](const DiagnosticDetail &d) {178        return d.source_location->column != it->source_location->column;179      });180      std::reverse(it, eq_end);181      it = eq_end;182    }183  };184  group(remaining_details);185 186  // Work through each detail in reverse order using the vector/stack.187  bool did_print = false;188  for (; !remaining_details.empty(); remaining_details.pop_back()) {189    const auto &detail = remaining_details.back();190    // Get the information to print this detail and remove it from the stack.191    // Print all the lines for all the other messages first.192    stream << std::string(padding, ' ');193    size_t x_pos = 1;194    for (auto &remaining_detail :195         llvm::ArrayRef(remaining_details).drop_back(1)) {196      uint16_t column = remaining_detail.source_location->column;197      // Is this a note with the same column as another diagnostic?198      if (column == detail.source_location->column)199        continue;200 201      if (column >= x_pos) {202        stream << std::string(column - x_pos, ' ') << vbar;203        x_pos = column + 1;204      }205    }206 207    uint16_t column = detail.source_location->column;208    // Print the line connecting the ^ with the error message.209    if (column >= x_pos)210      stream << std::string(column - x_pos, ' ') << joint << hbar << spacer;211 212    // Print a colorized string based on the message's severity type.213    PrintSeverity(stream, detail.severity);214 215    // Finally, print the message and start a new line.216    stream << detail.message << '\n';217    did_print = true;218  }219 220  // Print the non-located details.221  for (const DiagnosticDetail &detail : other_details) {222    PrintSeverity(stream, detail.severity);223    stream << detail.rendered << '\n';224    did_print = true;225  }226 227  // Print the hidden details as a last resort.228  if (!did_print)229    for (const DiagnosticDetail &detail : hidden_details) {230      PrintSeverity(stream, detail.severity);231      stream << detail.rendered << '\n';232    }233}234 235} // namespace lldb_private236