Coverage Report

Created: 2026-10-26 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/libsolutil/JSON.h
Line
Count
Source
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
/** @file JSON.h
19
 * @date 2016
20
 *
21
 * JSON related helpers
22
 */
23
24
#pragma once
25
26
#include <libsolutil/Assertions.h>
27
#include <nlohmann/json.hpp>
28
29
#include <compare>
30
#include <concepts>
31
#include <string>
32
#include <string_view>
33
#include <utility>
34
#include <optional>
35
#include <limits>
36
37
namespace solidity
38
{
39
40
using Json = nlohmann::json;
41
42
// Comparisons of tuples, pairs and containers of JSON values go through operator<=>, which must
43
// compare the values rather than only their types.
44
static_assert(std::same_as<decltype(std::declval<Json const&>() <=> std::declval<Json const&>()), std::partial_ordering>);
45
46
} // namespace solidity
47
48
namespace solidity::util
49
{
50
51
/// Removes members with null value recursively from (@a _json).
52
Json removeNullMembers(Json _json);
53
54
/// JSON printing format.
55
struct JsonFormat
56
{
57
  enum Format
58
  {
59
    Compact, // No unnecessary whitespace (including new lines and indentation)
60
    Pretty,  // Nicely indented, with new lines
61
  };
62
63
  static constexpr uint32_t defaultIndent = 2;
64
65
0
  bool operator==(JsonFormat const& _other) const noexcept { return (format == _other.format) && (indent == _other.indent); }
66
0
  bool operator!=(JsonFormat const& _other) const noexcept { return !(*this == _other); }
67
68
  Format format = Compact;
69
  uint32_t indent = defaultIndent;
70
};
71
72
/// Serialise the JSON object (@a _input) with indentation
73
std::string jsonPrettyPrint(Json const& _input);
74
75
/// Serialise the JSON object (@a _input) without indentation
76
std::string jsonCompactPrint(Json const& _input);
77
78
/// Serialise the JSON object (@a _input) using specified format (@a _format)
79
std::string jsonPrint(Json const& _input, JsonFormat const& _format);
80
81
/// Parse a JSON string (@a _input) with enabled strict-mode and writes resulting JSON object to (@a _json)
82
/// \param _input JSON input string
83
/// \param _json [out] resulting JSON object
84
/// \param _errs [out] Formatted error messages
85
/// \return \c true if the document was successfully parsed, \c false if an error occurred.
86
bool jsonParseStrict(std::string const& _input, Json& _json, std::string* _errs = nullptr);
87
88
/// Retrieves the value specified by @p _jsonPath by from a series of nested JSON dictionaries.
89
/// @param _jsonPath A dot-separated series of dictionary keys.
90
/// @param _node The node representing the start of the path.
91
/// @returns The value of the last key on the path. @a nullptr if any node on the path descends
92
/// into something that is not a dictionary or the key is not present.
93
std::optional<Json> jsonValueByPath(Json const& _node, std::string_view _jsonPath);
94
95
std::string removeNlohmannInternalErrorIdentifier(std::string const& _input);
96
97
namespace detail
98
{
99
100
template<typename T>
101
struct helper;
102
103
template<typename T, bool(Json::*checkMember)() const, T(Json::*convertMember)() const>
104
struct helper_impl
105
{
106
  static bool isOfType(Json const& _input)
107
0
  {
108
0
    return (_input.*checkMember)();
109
0
  }
110
  static T get(Json const& _input)
111
0
  {
112
0
    assertThrow(isOfType(_input), InvalidType,  "");
113
0
    return (_input.*convertMember)();
114
0
  }
115
  static T getOrDefault(Json const& _input, std::string const& _name, T _default = {})
116
0
  {
117
0
    T result = _default;
118
0
    if (_input.contains(_name) && isOfType(_input[_name]))
119
0
      result = (_input[_name].*convertMember)();
120
0
    return result;
121
0
  }
122
};
123
124
template<typename T, typename RT, bool(Json::*checkMember)() const, T(Json::*convertMember)() const>
125
struct helper_impl_with_range_check
126
{
127
  static bool isOfType(Json const& _input)
128
0
  {
129
0
    if ( (_input.*checkMember)())
130
0
    {
131
0
      T value = (_input.*convertMember)();
132
0
      return (value >= std::numeric_limits<RT>::min() && value <= std::numeric_limits<RT>::max());
133
0
    }
134
0
    return false;
135
0
  }
136
137
  static RT get(Json const& _input)
138
0
  {
139
0
    assertThrow(isOfType(_input), InvalidType,  "");
140
0
    return static_cast<RT>((_input.*convertMember)());
141
0
  }
142
143
  static RT getOrDefault(Json const& _input, std::string const& _name, RT _default = {})
144
0
  {
145
0
    RT value = _default;
146
0
    if (_input.contains(_name) && isOfType(_input[_name]))
147
0
      value = static_cast<RT>((_input[_name].*convertMember)());
148
0
    return value;
149
0
  }
150
};
151
152
template<> struct helper<Json::string_t>: helper_impl<Json::string_t, &Json::is_string, &Json::get<Json::string_t>> {};
153
template<> struct helper<Json::number_integer_t>: helper_impl<Json::number_integer_t, &Json::is_number_integer, &Json::get<Json::number_integer_t>> {};
154
template<> struct helper<Json::number_unsigned_t>: helper_impl<Json::number_unsigned_t, &Json::is_number_integer, &Json::get<Json::number_unsigned_t>> {};
155
template<> struct helper<Json::number_float_t>: helper_impl<Json::number_float_t, &Json::is_number, &Json::get<Json::number_float_t>> {};
156
template<> struct helper<Json::boolean_t>: helper_impl<Json::boolean_t, &Json::is_boolean, &Json::get<Json::boolean_t>> {};
157
158
template<> struct helper<int32_t>: helper_impl_with_range_check<Json::number_integer_t, int32_t, &Json::is_number_integer, &Json::get<Json::number_integer_t>> {};
159
template<> struct helper<int16_t>: helper_impl_with_range_check<Json::number_integer_t, int16_t, &Json::is_number_integer, &Json::get<Json::number_integer_t>> {};
160
template<> struct helper<int8_t>: helper_impl_with_range_check<Json::number_integer_t, int8_t, &Json::is_number_integer, &Json::get<Json::number_integer_t>> {};
161
template<> struct helper<uint32_t>: helper_impl_with_range_check<Json::number_unsigned_t, uint32_t, &Json::is_number_integer, &Json::get<Json::number_unsigned_t>> {};
162
template<> struct helper<uint16_t>: helper_impl_with_range_check<Json::number_unsigned_t, uint16_t, &Json::is_number_integer, &Json::get<Json::number_unsigned_t>> {};
163
template<> struct helper<uint8_t>: helper_impl_with_range_check<Json::number_integer_t, uint8_t, &Json::is_number_integer, &Json::get<Json::number_integer_t>> {};
164
template<> struct helper<float>: helper_impl_with_range_check<Json::number_float_t, float, &Json::is_number, &Json::get<Json::number_float_t>> {};
165
166
} // namespace detail
167
168
template<typename T>
169
bool isOfType(Json const& _input)
170
0
{
171
0
  return detail::helper<T>::isOfType(_input);
172
0
}
Unexecuted instantiation: bool solidity::util::isOfType<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(nlohmann::json_abi_v3_12_0::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, void> const&)
Unexecuted instantiation: bool solidity::util::isOfType<int>(nlohmann::json_abi_v3_12_0::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, void> const&)
173
174
template<typename T>
175
bool isOfTypeIfExists(Json const& _input, std::string const& _name)
176
0
{
177
0
  if (_input.contains(_name))
178
0
    return isOfType<T>(_input[_name]);
179
0
  return true;
180
0
}
Unexecuted instantiation: bool solidity::util::isOfTypeIfExists<int>(nlohmann::json_abi_v3_12_0::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, void> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: bool solidity::util::isOfTypeIfExists<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(nlohmann::json_abi_v3_12_0::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, void> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
181
182
template<typename T>
183
T get(Json const& _input)
184
0
{
185
0
  return detail::helper<T>::get(_input);
186
0
}
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > solidity::util::get<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(nlohmann::json_abi_v3_12_0::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, void> const&)
Unexecuted instantiation: int solidity::util::get<int>(nlohmann::json_abi_v3_12_0::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, void> const&)
187
188
template<typename T>
189
T getOrDefault(Json const& _input, std::string const& _name, T _default = {})
190
0
{
191
0
  return detail::helper<T>::getOrDefault(_input, _name, _default);
192
0
}
Unexecuted instantiation: int solidity::util::getOrDefault<int>(nlohmann::json_abi_v3_12_0::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, void> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > solidity::util::getOrDefault<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(nlohmann::json_abi_v3_12_0::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::json_abi_v3_12_0::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >, void> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
193
194
} // namespace solidity::util