From 354d5fa723d25515dbede41098c54ed35ef16276 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 5 Sep 2026 20:51:58 +0200 Subject: [PATCH] Broaden JSON_HEDLEY_WARN_UNUSED_RESULT coverage to pure query functions Add JSON_HEDLEY_WARN_UNUSED_RESULT to the unambiguous, const, side-effect-free observer functions whose return value is the entire purpose of the call: - dump() - type(), type_name() - all is_* predicates (is_primitive, is_structured, is_null, is_boolean, is_number, is_number_integer, is_number_unsigned, is_number_float, is_object, is_array, is_string, is_binary, is_discarded) - empty(), size(), max_size() - count(...) (both overloads) and contains(...) (all overloads, including the deprecated json_pointer overload) This mirrors the direction the standard library has taken with [[nodiscard]] on the analogous std::vector/std::map members, and catches real bugs such as `j.empty();` (meant `j.clear();`) or `j.contains(k);` with the result thrown away. Deliberately out of scope (left for a separate, later policy decision, per the issue): at(), value(), get*(), flatten(), unflatten(), patch(), merge_patch(), begin()/end(), comparison operators, erase(), and emplace(). Compiling the full test suite (tests/src/unit-*.cpp) with -Wunused-result -Werror uncovered one real hit: a regression test in unit-regression2.cpp called dump() purely to check it does not throw, discarding the result. Fixed by explicitly casting to void, since the call is intentionally result-less there. Fixes #5410 Signed-off-by: Niels Lohmann --- include/nlohmann/json.hpp | 25 +++++++++++++++++++++++++ single_include/nlohmann/json.hpp | 25 +++++++++++++++++++++++++ tests/src/unit-regression2.cpp | 3 ++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 6e8b2a772..57de49770 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1335,6 +1335,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief serialization /// @sa https://json.nlohmann.me/api/basic_json/dump/ + JSON_HEDLEY_WARN_UNUSED_RESULT string_t dump(const int indent = -1, const char indent_char = ' ', const bool ensure_ascii = false, @@ -1357,6 +1358,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return the type of the JSON value (explicit) /// @sa https://json.nlohmann.me/api/basic_json/type/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr value_t type() const noexcept { return m_data.m_type; @@ -1364,6 +1366,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether type is primitive /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_primitive() const noexcept { return is_null() || is_string() || is_boolean() || is_number() || is_binary(); @@ -1371,6 +1374,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether type is structured /// @sa https://json.nlohmann.me/api/basic_json/is_structured/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_structured() const noexcept { return is_array() || is_object(); @@ -1378,6 +1382,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is null /// @sa https://json.nlohmann.me/api/basic_json/is_null/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_null() const noexcept { return m_data.m_type == value_t::null; @@ -1385,6 +1390,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is a boolean /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_boolean() const noexcept { return m_data.m_type == value_t::boolean; @@ -1392,6 +1398,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is a number /// @sa https://json.nlohmann.me/api/basic_json/is_number/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_number() const noexcept { return is_number_integer() || is_number_float(); @@ -1399,6 +1406,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is an integer number /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_number_integer() const noexcept { return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned; @@ -1406,6 +1414,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is an unsigned integer number /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_number_unsigned() const noexcept { return m_data.m_type == value_t::number_unsigned; @@ -1413,6 +1422,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is a floating-point number /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_number_float() const noexcept { return m_data.m_type == value_t::number_float; @@ -1420,6 +1430,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is an object /// @sa https://json.nlohmann.me/api/basic_json/is_object/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_object() const noexcept { return m_data.m_type == value_t::object; @@ -1427,6 +1438,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is an array /// @sa https://json.nlohmann.me/api/basic_json/is_array/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_array() const noexcept { return m_data.m_type == value_t::array; @@ -1434,6 +1446,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is a string /// @sa https://json.nlohmann.me/api/basic_json/is_string/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_string() const noexcept { return m_data.m_type == value_t::string; @@ -1441,6 +1454,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is a binary array /// @sa https://json.nlohmann.me/api/basic_json/is_binary/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_binary() const noexcept { return m_data.m_type == value_t::binary; @@ -1448,6 +1462,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is discarded /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_discarded() const noexcept { return m_data.m_type == value_t::discarded; @@ -2779,6 +2794,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief returns the number of occurrences of a key in a JSON object /// @sa https://json.nlohmann.me/api/basic_json/count/ + JSON_HEDLEY_WARN_UNUSED_RESULT size_type count(const typename object_t::key_type& key) const { // return 0 for all nonobject types @@ -2789,6 +2805,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/count/ template::value, int> = 0> + JSON_HEDLEY_WARN_UNUSED_RESULT size_type count(KeyType && key) const { // return 0 for all nonobject types @@ -2797,6 +2814,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief check the existence of an element in a JSON object /// @sa https://json.nlohmann.me/api/basic_json/contains/ + JSON_HEDLEY_WARN_UNUSED_RESULT bool contains(const typename object_t::key_type& key) const { return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end(); @@ -2806,6 +2824,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/contains/ template::value, int> = 0> + JSON_HEDLEY_WARN_UNUSED_RESULT bool contains(KeyType && key) const { return is_object() && m_data.m_value.object->find(std::forward(key)) != m_data.m_value.object->end(); @@ -2813,12 +2832,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief check the existence of an element in a JSON object given a JSON pointer /// @sa https://json.nlohmann.me/api/basic_json/contains/ + JSON_HEDLEY_WARN_UNUSED_RESULT bool contains(const json_pointer& ptr) const { return ptr.contains(this); } template::value, int> = 0> + JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) bool contains(const typename ::nlohmann::json_pointer& ptr) const { @@ -2974,6 +2995,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief checks whether the container is empty. /// @sa https://json.nlohmann.me/api/basic_json/empty/ + JSON_HEDLEY_WARN_UNUSED_RESULT bool empty() const noexcept { switch (m_data.m_type) @@ -3013,6 +3035,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief returns the number of elements /// @sa https://json.nlohmann.me/api/basic_json/size/ + JSON_HEDLEY_WARN_UNUSED_RESULT size_type size() const noexcept { switch (m_data.m_type) @@ -3052,6 +3075,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief returns the maximum possible number of elements /// @sa https://json.nlohmann.me/api/basic_json/max_size/ + JSON_HEDLEY_WARN_UNUSED_RESULT size_type max_size() const noexcept { switch (m_data.m_type) @@ -4241,6 +4265,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return the type as string /// @sa https://json.nlohmann.me/api/basic_json/type_name/ + JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_RETURNS_NON_NULL const char* type_name() const noexcept { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index b0b6a3f5f..c1b098cc0 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -22763,6 +22763,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief serialization /// @sa https://json.nlohmann.me/api/basic_json/dump/ + JSON_HEDLEY_WARN_UNUSED_RESULT string_t dump(const int indent = -1, const char indent_char = ' ', const bool ensure_ascii = false, @@ -22785,6 +22786,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return the type of the JSON value (explicit) /// @sa https://json.nlohmann.me/api/basic_json/type/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr value_t type() const noexcept { return m_data.m_type; @@ -22792,6 +22794,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether type is primitive /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_primitive() const noexcept { return is_null() || is_string() || is_boolean() || is_number() || is_binary(); @@ -22799,6 +22802,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether type is structured /// @sa https://json.nlohmann.me/api/basic_json/is_structured/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_structured() const noexcept { return is_array() || is_object(); @@ -22806,6 +22810,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is null /// @sa https://json.nlohmann.me/api/basic_json/is_null/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_null() const noexcept { return m_data.m_type == value_t::null; @@ -22813,6 +22818,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is a boolean /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_boolean() const noexcept { return m_data.m_type == value_t::boolean; @@ -22820,6 +22826,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is a number /// @sa https://json.nlohmann.me/api/basic_json/is_number/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_number() const noexcept { return is_number_integer() || is_number_float(); @@ -22827,6 +22834,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is an integer number /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_number_integer() const noexcept { return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned; @@ -22834,6 +22842,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is an unsigned integer number /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_number_unsigned() const noexcept { return m_data.m_type == value_t::number_unsigned; @@ -22841,6 +22850,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is a floating-point number /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_number_float() const noexcept { return m_data.m_type == value_t::number_float; @@ -22848,6 +22858,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is an object /// @sa https://json.nlohmann.me/api/basic_json/is_object/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_object() const noexcept { return m_data.m_type == value_t::object; @@ -22855,6 +22866,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is an array /// @sa https://json.nlohmann.me/api/basic_json/is_array/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_array() const noexcept { return m_data.m_type == value_t::array; @@ -22862,6 +22874,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is a string /// @sa https://json.nlohmann.me/api/basic_json/is_string/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_string() const noexcept { return m_data.m_type == value_t::string; @@ -22869,6 +22882,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is a binary array /// @sa https://json.nlohmann.me/api/basic_json/is_binary/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_binary() const noexcept { return m_data.m_type == value_t::binary; @@ -22876,6 +22890,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return whether value is discarded /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/ + JSON_HEDLEY_WARN_UNUSED_RESULT constexpr bool is_discarded() const noexcept { return m_data.m_type == value_t::discarded; @@ -24207,6 +24222,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief returns the number of occurrences of a key in a JSON object /// @sa https://json.nlohmann.me/api/basic_json/count/ + JSON_HEDLEY_WARN_UNUSED_RESULT size_type count(const typename object_t::key_type& key) const { // return 0 for all nonobject types @@ -24217,6 +24233,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/count/ template::value, int> = 0> + JSON_HEDLEY_WARN_UNUSED_RESULT size_type count(KeyType && key) const { // return 0 for all nonobject types @@ -24225,6 +24242,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief check the existence of an element in a JSON object /// @sa https://json.nlohmann.me/api/basic_json/contains/ + JSON_HEDLEY_WARN_UNUSED_RESULT bool contains(const typename object_t::key_type& key) const { return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end(); @@ -24234,6 +24252,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @sa https://json.nlohmann.me/api/basic_json/contains/ template::value, int> = 0> + JSON_HEDLEY_WARN_UNUSED_RESULT bool contains(KeyType && key) const { return is_object() && m_data.m_value.object->find(std::forward(key)) != m_data.m_value.object->end(); @@ -24241,12 +24260,14 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief check the existence of an element in a JSON object given a JSON pointer /// @sa https://json.nlohmann.me/api/basic_json/contains/ + JSON_HEDLEY_WARN_UNUSED_RESULT bool contains(const json_pointer& ptr) const { return ptr.contains(this); } template::value, int> = 0> + JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer) // NOLINT(readability/alt_tokens) bool contains(const typename ::nlohmann::json_pointer& ptr) const { @@ -24402,6 +24423,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief checks whether the container is empty. /// @sa https://json.nlohmann.me/api/basic_json/empty/ + JSON_HEDLEY_WARN_UNUSED_RESULT bool empty() const noexcept { switch (m_data.m_type) @@ -24441,6 +24463,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief returns the number of elements /// @sa https://json.nlohmann.me/api/basic_json/size/ + JSON_HEDLEY_WARN_UNUSED_RESULT size_type size() const noexcept { switch (m_data.m_type) @@ -24480,6 +24503,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief returns the maximum possible number of elements /// @sa https://json.nlohmann.me/api/basic_json/max_size/ + JSON_HEDLEY_WARN_UNUSED_RESULT size_type max_size() const noexcept { switch (m_data.m_type) @@ -25669,6 +25693,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief return the type as string /// @sa https://json.nlohmann.me/api/basic_json/type_name/ + JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_RETURNS_NON_NULL const char* type_name() const noexcept { diff --git a/tests/src/unit-regression2.cpp b/tests/src/unit-regression2.cpp index 2e7450e2e..8f2397c68 100644 --- a/tests/src/unit-regression2.cpp +++ b/tests/src/unit-regression2.cpp @@ -639,7 +639,8 @@ TEST_CASE("regression tests 2") s += static_cast(i); } dump_test["1"] = s; - dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace); + // dump() is nodiscard; this only checks that dumping does not throw/crash + (void)dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace); } }