Compare commits

..
Author SHA1 Message Date
Niels Lohmann 379756e92e json_view: no byte range in exceptions about a removed value
#5990 dropped the found flag from diagnostics(), reasoning that a value
value_path() does not find leaves no tokens, like the root. But the node
of a value that is no longer part of the document still holds the bytes
it had in the source, so with JSON_DIAGNOSTICS and
JSON_DIAGNOSTIC_POSITIONS its exceptions gained "(bytes 1-4)" for text
that is no longer there. The test #5997 added for exactly this case
(unit-json_view_positions.cpp, "views of values that are no longer part
of the document") has failed on develop since both were merged.

Restore the flag: a value that is not found gets no context, the root
keeps its byte range.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-02 19:08:09 +01:00
4 changed files with 26 additions and 20 deletions

No files matched your search

+6 -6
View File
@@ -1168,20 +1168,20 @@ indent_done:
if (negative) if (negative)
{ {
++p; ++p;
if (NLOHMANN_VIEW_UNLIKELY(cur() < '0' || cur() > '9'))
{
return fail(error_code::number_after_minus);
}
} }
const unsigned char* const int_start = p; const unsigned char* const int_start = p;
if (cur() == '0') if (cur() == '0')
{ {
++p; ++p;
} }
else if (!negative || NLOHMANN_VIEW_LIKELY(cur() >= '1' && cur() <= '9'))
{
// (without a sign, the dispatch saw a digit)
p = skip_digits(p + 1, e);
}
else else
{ {
// (a digit: the dispatch or the check after the sign saw it) return fail(error_code::number_after_minus);
p = skip_digits(p + 1, e);
} }
const auto int_digits = static_cast<std::size_t>(p - int_start); const auto int_digits = static_cast<std::size_t>(p - int_start);
std::size_t frac_digits = 0; std::size_t frac_digits = 0;
+5 -2
View File
@@ -230,7 +230,8 @@ void value_range(const document_data& d, const node* n, std::size_t& start, std:
/// the context basic_json puts in front of the message of an exception about /// the context basic_json puts in front of the message of an exception about
/// a value: "(/path) " with JSON_DIAGNOSTICS (none for the root), then /// a value: "(/path) " with JSON_DIAGNOSTICS (none for the root), then
/// "(bytes a-b) " with JSON_DIAGNOSTIC_POSITIONS (also for the root) /// "(bytes a-b) " with JSON_DIAGNOSTIC_POSITIONS (also for the root); with
/// JSON_DIAGNOSTICS, nothing for a value that is no longer part of the document
/// ///
/// This and the throw helpers that take an error_site are templates, so that /// This and the throw helpers that take an error_site are templates, so that
/// the path and range code is instantiated only where an exception can be /// the path and range code is instantiated only where an exception can be
@@ -251,10 +252,12 @@ std::string diagnostics(const error_site site)
std::string context; std::string context;
#if JSON_DIAGNOSTICS #if JSON_DIAGNOSTICS
std::vector<std::string> tokens; std::vector<std::string> tokens;
// a value that is no longer part of the document has no path, and its
// node still holds the bytes it had in the source: no context at all
const bool found = edited ? value_path<true>(d, site.value(), tokens) : value_path<false>(d, site.value(), tokens); const bool found = edited ? value_path<true>(d, site.value(), tokens) : value_path<false>(d, site.value(), tokens);
if (!found) if (!found)
{ {
// a value that is not found has no path, and with it no bytes // context is still empty; returning it keeps the copy elided (-Wnrvo)
return context; return context;
} }
if (!tokens.empty()) if (!tokens.empty())
+11 -8
View File
@@ -2473,20 +2473,20 @@ indent_done:
if (negative) if (negative)
{ {
++p; ++p;
if (NLOHMANN_VIEW_UNLIKELY(cur() < '0' || cur() > '9'))
{
return fail(error_code::number_after_minus);
}
} }
const unsigned char* const int_start = p; const unsigned char* const int_start = p;
if (cur() == '0') if (cur() == '0')
{ {
++p; ++p;
} }
else if (!negative || NLOHMANN_VIEW_LIKELY(cur() >= '1' && cur() <= '9'))
{
// (without a sign, the dispatch saw a digit)
p = skip_digits(p + 1, e);
}
else else
{ {
// (a digit: the dispatch or the check after the sign saw it) return fail(error_code::number_after_minus);
p = skip_digits(p + 1, e);
} }
const auto int_digits = static_cast<std::size_t>(p - int_start); const auto int_digits = static_cast<std::size_t>(p - int_start);
std::size_t frac_digits = 0; std::size_t frac_digits = 0;
@@ -5059,7 +5059,8 @@ void value_range(const document_data& d, const node* n, std::size_t& start, std:
/// the context basic_json puts in front of the message of an exception about /// the context basic_json puts in front of the message of an exception about
/// a value: "(/path) " with JSON_DIAGNOSTICS (none for the root), then /// a value: "(/path) " with JSON_DIAGNOSTICS (none for the root), then
/// "(bytes a-b) " with JSON_DIAGNOSTIC_POSITIONS (also for the root) /// "(bytes a-b) " with JSON_DIAGNOSTIC_POSITIONS (also for the root); with
/// JSON_DIAGNOSTICS, nothing for a value that is no longer part of the document
/// ///
/// This and the throw helpers that take an error_site are templates, so that /// This and the throw helpers that take an error_site are templates, so that
/// the path and range code is instantiated only where an exception can be /// the path and range code is instantiated only where an exception can be
@@ -5080,10 +5081,12 @@ std::string diagnostics(const error_site site)
std::string context; std::string context;
#if JSON_DIAGNOSTICS #if JSON_DIAGNOSTICS
std::vector<std::string> tokens; std::vector<std::string> tokens;
// a value that is no longer part of the document has no path, and its
// node still holds the bytes it had in the source: no context at all
const bool found = edited ? value_path<true>(d, site.value(), tokens) : value_path<false>(d, site.value(), tokens); const bool found = edited ? value_path<true>(d, site.value(), tokens) : value_path<false>(d, site.value(), tokens);
if (!found) if (!found)
{ {
// a value that is not found has no path, and with it no bytes // context is still empty; returning it keeps the copy elided (-Wnrvo)
return context; return context;
} }
if (!tokens.empty()) if (!tokens.empty())
+4 -4
View File
@@ -505,8 +505,8 @@ struct locale_switching_token
{ {
using value_type = char; using value_type = char;
locale_switching_token(std::string text_, std::string switch_to_) locale_switching_token(std::string text_, const char* switch_to_)
: text(std::move(text_)), switch_to(std::move(switch_to_)) : text(std::move(text_)), switch_to(switch_to_)
{} {}
std::size_t size() const std::size_t size() const
@@ -523,13 +523,13 @@ struct locale_switching_token
{ {
if (!switched) if (!switched)
{ {
switched = std::setlocale(LC_NUMERIC, switch_to.c_str()) != nullptr; switched = std::setlocale(LC_NUMERIC, switch_to) != nullptr;
} }
return &text[0]; return &text[0];
} }
std::string text; std::string text;
std::string switch_to; const char* switch_to;
bool switched = false; bool switched = false;
}; };