This source file includes following definitions.
- GetNthLine
- FillRangeOnLine
- OutputHighlighedPosition
- help_text_
- help_text_
- help_text_
- help_text_
- help_text_
- PrintToStdout
- AppendSubErr
- InternalPrintToStdout
#include "tools/gn/err.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "tools/gn/filesystem_utils.h"
#include "tools/gn/input_file.h"
#include "tools/gn/parse_tree.h"
#include "tools/gn/standard_out.h"
#include "tools/gn/tokenizer.h"
#include "tools/gn/value.h"
namespace {
std::string GetNthLine(const base::StringPiece& data, int n) {
size_t line_off = Tokenizer::ByteOffsetOfNthLine(data, n);
size_t end = line_off + 1;
while (end < data.size() && !Tokenizer::IsNewline(data, end))
end++;
return data.substr(line_off, end - line_off).as_string();
}
void FillRangeOnLine(const LocationRange& range, int line_number,
std::string* line) {
if (range.begin().line_number() != line_number &&
range.end().line_number() != line_number)
return;
int begin_char;
if (range.begin().line_number() < line_number)
begin_char = 0;
else
begin_char = range.begin().char_offset() - 1;
int end_char;
if (range.end().line_number() > line_number)
end_char = static_cast<int>(line->size());
else
end_char = range.end().char_offset() - 1;
CHECK(end_char >= begin_char);
CHECK(begin_char >= 0 && begin_char <= static_cast<int>(line->size()));
CHECK(end_char >= 0 && end_char <= static_cast<int>(line->size()));
for (int i = begin_char; i < end_char; i++)
line->at(i) = '-';
}
void OutputHighlighedPosition(const Location& location,
const Err::RangeList& ranges,
size_t line_length) {
std::string highlight;
highlight.resize(line_length);
for (size_t i = 0; i < line_length; i++)
highlight[i] = ' ';
for (size_t i = 0; i < ranges.size(); i++)
FillRangeOnLine(ranges[i], location.line_number(), &highlight);
highlight.push_back(' ');
CHECK(location.char_offset() - 1 >= 0 &&
location.char_offset() - 1 < static_cast<int>(highlight.size()));
highlight[location.char_offset() - 1] = '^';
while (!highlight.empty() && highlight[highlight.size() - 1] == ' ')
highlight.resize(highlight.size() - 1);
highlight += "\n";
OutputString(highlight, DECORATION_BLUE);
}
}
Err::Err() : has_error_(false) {
}
Err::Err(const Location& location,
const std::string& msg,
const std::string& help)
: has_error_(true),
location_(location),
message_(msg),
help_text_(help) {
}
Err::Err(const LocationRange& range,
const std::string& msg,
const std::string& help)
: has_error_(true),
location_(range.begin()),
message_(msg),
help_text_(help) {
ranges_.push_back(range);
}
Err::Err(const Token& token,
const std::string& msg,
const std::string& help)
: has_error_(true),
location_(token.location()),
message_(msg),
help_text_(help) {
ranges_.push_back(token.range());
}
Err::Err(const ParseNode* node,
const std::string& msg,
const std::string& help_text)
: has_error_(true),
message_(msg),
help_text_(help_text) {
if (node) {
LocationRange range = node->GetRange();
location_ = range.begin();
ranges_.push_back(range);
}
}
Err::Err(const Value& value,
const std::string msg,
const std::string& help_text)
: has_error_(true),
message_(msg),
help_text_(help_text) {
if (value.origin()) {
LocationRange range = value.origin()->GetRange();
location_ = range.begin();
ranges_.push_back(range);
}
}
Err::~Err() {
}
void Err::PrintToStdout() const {
InternalPrintToStdout(false);
}
void Err::AppendSubErr(const Err& err) {
sub_errs_.push_back(err);
}
void Err::InternalPrintToStdout(bool is_sub_err) const {
DCHECK(has_error_);
if (!is_sub_err)
OutputString("ERROR ", DECORATION_RED);
const InputFile* input_file = location_.file();
std::string loc_str = location_.Describe(true);
if (!loc_str.empty()) {
if (is_sub_err)
loc_str.insert(0, "See ");
else
loc_str.insert(0, "at ");
loc_str.append(": ");
}
OutputString(loc_str + message_ + "\n");
if (input_file) {
std::string line = GetNthLine(input_file->contents(),
location_.line_number());
if (!base::ContainsOnlyChars(line, base::kWhitespaceASCII)) {
OutputString(line + "\n", DECORATION_DIM);
OutputHighlighedPosition(location_, ranges_, line.size());
}
}
if (!help_text_.empty())
OutputString(help_text_ + "\n");
for (size_t i = 0; i < sub_errs_.size(); i++)
sub_errs_[i].InternalPrintToStdout(true);
}