LCOV - code coverage report
Current view: top level - gcc - json.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 96.1 % 545 524
Test Date: 2026-05-11 19:44:49 Functions: 94.9 % 59 56
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* JSON trees
       2              :    Copyright (C) 2017-2026 Free Software Foundation, Inc.
       3              :    Contributed by David Malcolm <dmalcolm@redhat.com>.
       4              : 
       5              : This file is part of GCC.
       6              : 
       7              : GCC is free software; you can redistribute it and/or modify it under
       8              : the terms of the GNU General Public License as published by the Free
       9              : Software Foundation; either version 3, or (at your option) any later
      10              : version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15              : for more details.
      16              : 
      17              : You should have received a copy of the GNU General Public License
      18              : along with GCC; see the file COPYING3.  If not see
      19              : <http://www.gnu.org/licenses/>.  */
      20              : 
      21              : #include "config.h"
      22              : #include "system.h"
      23              : #include "coretypes.h"
      24              : #include "json.h"
      25              : #include "pretty-print.h"
      26              : #include "math.h"
      27              : #include "selftest.h"
      28              : 
      29              : using namespace json;
      30              : 
      31              : /* Print a JSON string to PP, escaping '"', control characters,
      32              :    and embedded null bytes.
      33              :    The string is required to be UTF-8 encoded.  */
      34              : 
      35              : static void
      36      1288802 : print_escaped_json_string (pretty_printer *pp,
      37              :                            const char *utf8_str,
      38              :                            size_t len)
      39              : {
      40      1288802 :   pp_character (pp, '"');
      41     17693822 :   for (size_t i = 0; i != len; ++i)
      42              :     {
      43     16405020 :       char ch = utf8_str[i];
      44     16405020 :       switch (ch)
      45              :         {
      46         3018 :         case '"':
      47         3018 :           pp_string (pp, "\\\"");
      48         3018 :           break;
      49         1609 :         case '\\':
      50         1609 :           pp_string (pp, "\\\\");
      51         1609 :           break;
      52            8 :         case '\b':
      53            8 :           pp_string (pp, "\\b");
      54            8 :           break;
      55            8 :         case '\f':
      56            8 :           pp_string (pp, "\\f");
      57            8 :           break;
      58        50377 :         case '\n':
      59        50377 :           pp_string (pp, "\\n");
      60        50377 :           break;
      61            8 :         case '\r':
      62            8 :           pp_string (pp, "\\r");
      63            8 :           break;
      64         2800 :         case '\t':
      65         2800 :           pp_string (pp, "\\t");
      66         2800 :           break;
      67            4 :         case '\0':
      68            4 :           pp_string (pp, "\\0");
      69            4 :           break;
      70     16347188 :         default:
      71     16347188 :           pp_character (pp, ch);
      72              :         }
      73              :     }
      74      1288802 :   pp_character (pp, '"');
      75      1288802 : }
      76              : 
      77              : /* class pointer::token.  */
      78              : 
      79      4145917 : pointer::token::token ()
      80              : {
      81      4145917 :   m_parent = nullptr;
      82      4145917 :   m_data.u_member = nullptr;
      83      4145917 :   m_kind = kind::root_value;
      84      4145917 : }
      85              : 
      86      3342122 : pointer::token::token (json::object &parent, const char *member)
      87              : {
      88      3342122 :   m_parent = &parent;
      89      3342122 :   m_data.u_member = xstrdup (member); // ideally we'd share
      90      3342122 :   m_kind = kind::object_member;
      91      3342122 : }
      92              : 
      93       797821 : pointer::token::token (json::array &parent, size_t index)
      94              : {
      95       797821 :   m_parent = &parent;
      96       797821 :   m_data.u_index = index;
      97       797821 :   m_kind = kind::array_index;
      98       797821 : }
      99              : 
     100      8284484 : pointer::token::~token ()
     101              : {
     102      8284484 :   if (m_kind == kind::object_member)
     103              :     {
     104      3340968 :       gcc_assert (m_data.u_member);
     105      3340968 :       free (m_data.u_member);
     106              :     }
     107      8284484 : }
     108              : 
     109              : pointer::token &
     110      4139943 : pointer::token::operator= (pointer::token &&other)
     111              : {
     112      4139943 :   m_parent = other.m_parent;
     113      4139943 :   m_data = other.m_data;
     114      4139943 :   m_kind = other.m_kind;
     115              : 
     116      4139943 :   other.m_parent = nullptr;
     117      4139943 :   other.m_data.u_member = nullptr;
     118      4139943 :   other.m_kind = kind::root_value;
     119              : 
     120      4139943 :   return *this;
     121              : }
     122              : 
     123              : /* Print this to PP as an RFC 6901 section 3 reference-token.  */
     124              : 
     125              : void
     126           92 : pointer::token::print (pretty_printer *pp) const
     127              : {
     128           92 :   switch (m_kind)
     129              :     {
     130              :     case kind::root_value:
     131              :       break;
     132              : 
     133           24 :     case kind::object_member:
     134           24 :       {
     135           96 :         for (const char *ch = m_data.u_member; *ch; ++ch)
     136              :           {
     137           72 :             switch (*ch)
     138              :               {
     139            4 :               case '~':
     140            4 :                 pp_string (pp, "~0");
     141            4 :                 break;
     142            4 :               case '/':
     143            4 :                 pp_string (pp, "~1");
     144            4 :                 break;
     145           64 :               default:
     146           64 :                 pp_character (pp, *ch);
     147           64 :                 break;
     148              :               }
     149              :           }
     150              :       }
     151              :       break;
     152              : 
     153            8 :     case kind::array_index:
     154            8 :       pp_scalar (pp, HOST_SIZE_T_PRINT_UNSIGNED, (fmt_size_t) m_data.u_index);
     155            8 :       break;
     156              :     }
     157           92 : }
     158              : 
     159              : /* class json::value.  */
     160              : 
     161              : /* Dump this json::value tree to OUTF.
     162              : 
     163              :    The key/value pairs of json::objects are printed in the order
     164              :    in which the keys were originally inserted.  */
     165              : 
     166              : void
     167          114 : value::dump (FILE *outf, bool formatted) const
     168              : {
     169          114 :   pretty_printer pp;
     170          114 :   pp_buffer (&pp)->m_stream = outf;
     171          114 :   print (&pp, formatted);
     172          114 :   pp_flush (&pp);
     173          114 : }
     174              : 
     175              : /* A convenience function for debugging.
     176              :    Dump to stderr with formatting, and a trailing newline. */
     177              : 
     178              : void
     179            0 : value::dump () const
     180              : {
     181            0 :   dump (stderr, true);
     182            0 :   fprintf (stderr, "\n");
     183            0 : }
     184              : 
     185              : /* A deterministic total ordering for comparing json values, so that we
     186              :    can e.g. put them in std::map.
     187              : 
     188              :    This is intended to follow the condition for equality described in
     189              :    the JSON Schema standard (§4.3, “Instance equality”), as referenced
     190              :    by SARIF v2.1.0 (§3.7.3 "Array properties with unique values"), but has
     191              :    the following limitations:
     192              :    - numbers are supposed to be checked for "the same mathematical value",
     193              :    but in this implementation int vs float numbers won't compare as equal,
     194              :    and float number comparison is bitwise
     195              :    - strings are supposed to be "the same codepoint-for-codepoint", but
     196              :    this implementation doesn't take into account canonicalization issues.  */
     197              : 
     198              : int
     199        16798 : value::compare (const value &val_a, const value &val_b)
     200              : {
     201        16798 :   enum kind kind_a = val_a.get_kind ();
     202        16798 :   enum kind kind_b = val_b.get_kind ();
     203        16798 :   if (kind_a != kind_b)
     204           32 :     return (int)kind_a - (int)kind_b;
     205              : 
     206        16766 :   switch (kind_a)
     207              :     {
     208            0 :     default:
     209            0 :       gcc_unreachable ();
     210              : 
     211         5402 :     case JSON_OBJECT:
     212         5402 :       {
     213         5402 :         const object &obj_a = (const object &)val_a;
     214         5402 :         const object &obj_b = (const object &)val_b;
     215         5402 :         return object::compare (obj_a, obj_b);
     216              :       }
     217           56 :       break;
     218              : 
     219           56 :     case JSON_ARRAY:
     220           56 :       {
     221           56 :         const array &arr_a = (const array &)val_a;
     222           56 :         const array &arr_b = (const array &)val_b;
     223          128 :         if (int cmp_size = (int)arr_a.size () - (int)arr_b.size ())
     224              :           return cmp_size;
     225           64 :         for (size_t idx = 0; idx < arr_a.size (); ++idx)
     226           24 :           if (int cmp_element = compare (*arr_a[idx], *arr_b[idx]))
     227              :             return cmp_element;
     228              :         return 0;
     229              :       }
     230           81 :       break;
     231              : 
     232           81 :     case JSON_INTEGER:
     233           81 :       {
     234           81 :         const integer_number &int_a = (const integer_number &)val_a;
     235           81 :         const integer_number &int_b = (const integer_number &)val_b;
     236           81 :         return int_a.get () - int_b.get ();
     237              :       }
     238           32 :       break;
     239              : 
     240           32 :     case JSON_FLOAT:
     241           32 :       {
     242           32 :         const float_number &float_a = (const float_number &)val_a;
     243           32 :         const float_number &float_b = (const float_number &)val_b;
     244           32 :         union u
     245              :         {
     246              :           double u_double;
     247              :           char u_buf[sizeof(double)];
     248              :         };
     249           32 :         union u u_a, u_b;
     250           32 :         u_a.u_double = float_a.get ();
     251           32 :         u_b.u_double = float_b.get ();
     252           32 :         return memcmp (&u_a, &u_b, sizeof(double));
     253              :       }
     254        11155 :       break;
     255              : 
     256        11155 :     case JSON_STRING:
     257        11155 :       {
     258        11155 :         const string &str_a = (const string &)val_a;
     259        11155 :         const string &str_b = (const string &)val_b;
     260        11155 :         return strcmp (str_a.get_string (), str_b.get_string ());
     261              :       }
     262              :       break;
     263              : 
     264              :     case JSON_TRUE:
     265              :     case JSON_FALSE:
     266              :     case JSON_NULL:
     267              :       /* All instances of literals compare equal to instances
     268              :          of the same literal.  */
     269              :       return 0;
     270              :     }
     271              : }
     272              : 
     273              : /* Print this value's JSON Pointer to PP.  */
     274              : 
     275              : void
     276           60 : value::print_pointer (pretty_printer *pp) const
     277              : {
     278              :   /* Get path from this value to root.  */
     279           60 :   auto_vec<const pointer::token *> ancestry;
     280          152 :   for (auto *iter = this; iter; iter = iter->m_pointer_token.m_parent)
     281           92 :     ancestry.safe_push (&iter->m_pointer_token);
     282              : 
     283              :   /* Walk backward, going from root to this value.  */
     284           60 :   ancestry.reverse ();
     285           60 :   bool first = true;
     286          272 :   for (auto iter : ancestry)
     287              :     {
     288           92 :       if (first)
     289              :         first = false;
     290              :       else
     291           32 :         pp_character (pp, '/');
     292           92 :       iter->print (pp);
     293              :     }
     294           60 : }
     295              : 
     296              : /* class json::object, a subclass of json::value, representing
     297              :    an ordered collection of key/value pairs.  */
     298              : 
     299              : /* json:object's dtor.  */
     300              : 
     301      1497420 : object::~object ()
     302              : {
     303     10780496 :   for (map_t::iterator it = m_map.begin (); it != m_map.end (); ++it)
     304              :     {
     305      3340890 :       free (const_cast <char *>((*it).first));
     306      3340890 :       delete ((*it).second);
     307              :     }
     308      1497420 : }
     309              : 
     310              : /* Implementation of json::value::print for json::object.  */
     311              : 
     312              : void
     313       246070 : object::print (pretty_printer *pp, bool formatted) const
     314              : {
     315       246070 :   pp_character (pp, '{');
     316       246070 :   if (formatted)
     317        10552 :     pp_indentation (pp) += 1;
     318              : 
     319              :   /* Iterate in the order that the keys were inserted.  */
     320              :   unsigned i;
     321              :   const char *key;
     322      1043786 :   FOR_EACH_VEC_ELT (m_keys, i, key)
     323              :     {
     324       797716 :       if (i > 0)
     325              :         {
     326       551654 :           pp_string (pp, ",");
     327       551654 :           if (formatted)
     328              :             {
     329        14613 :               pp_newline (pp);
     330        14613 :               pp_indent (pp);
     331              :             }
     332              :           else
     333       537041 :             pp_space (pp);
     334              :         }
     335       797716 :       map_t &mut_map = const_cast<map_t &> (m_map);
     336       797716 :       value *value = *mut_map.get (key);
     337       797716 :       print_escaped_json_string (pp, key, strlen (key));
     338       797716 :       pp_string (pp, ": ");
     339       797716 :       const int indent = strlen (key) + 4;
     340       797716 :       if (formatted)
     341        25157 :         pp_indentation (pp) += indent;
     342       797716 :       value->print (pp, formatted);
     343       797716 :       if (formatted)
     344        25157 :         pp_indentation (pp) -= indent;
     345              :     }
     346       246070 :   if (formatted)
     347        10552 :     pp_indentation (pp) -= 1;
     348       246070 :   pp_character (pp, '}');
     349       246070 : }
     350              : 
     351              : std::unique_ptr<value>
     352            4 : object::clone () const
     353              : {
     354            4 :   return clone_as_object ();
     355              : }
     356              : 
     357              : std::unique_ptr<object>
     358            4 : object::clone_as_object () const
     359              : {
     360            4 :   auto result = std::make_unique<object> ();
     361              : 
     362              :   /* Iterate in the order that the keys were inserted.  */
     363            4 :   unsigned i;
     364            4 :   const char *key;
     365            8 :   FOR_EACH_VEC_ELT (m_keys, i, key)
     366              :     {
     367            4 :       map_t &mut_map = const_cast<map_t &> (m_map);
     368            4 :       value *value = *mut_map.get (key);
     369            4 :       result->set (key, value->clone ());
     370              :     }
     371              : 
     372            4 :   return result;
     373              : }
     374              : 
     375              : /* Set the json::value * for KEY, taking ownership of V
     376              :    (and taking a copy of KEY if necessary).  */
     377              : 
     378              : void
     379      3342122 : object::set (const char *key, value *v)
     380              : {
     381      3342122 :   gcc_assert (key);
     382      3342122 :   gcc_assert (v);
     383              : 
     384      3342122 :   value **ptr = m_map.get (key);
     385      3342122 :   if (ptr)
     386              :     {
     387              :       /* If the key is already present, delete the existing value
     388              :          and overwrite it.  */
     389           78 :       delete *ptr;
     390           78 :       *ptr = v;
     391              :     }
     392              :   else
     393              :     {
     394              :       /* If the key wasn't already present, take a copy of the key,
     395              :          and store the value.  */
     396      3342044 :       char *owned_key = xstrdup (key);
     397      3342044 :       m_map.put (owned_key, v);
     398      3342044 :       m_keys.safe_push (owned_key);
     399              :     }
     400              : 
     401      3342122 :   v->m_pointer_token = pointer::token (*this, key);
     402      3342122 : }
     403              : 
     404              : /* Get the json::value * for KEY.
     405              : 
     406              :    The object retains ownership of the value.  */
     407              : 
     408              : value *
     409        25840 : object::get (const char *key) const
     410              : {
     411        25840 :   gcc_assert (key);
     412              : 
     413        25840 :   value **ptr = const_cast <map_t &> (m_map).get (key);
     414        25840 :   if (ptr)
     415        23277 :     return *ptr;
     416              :   else
     417              :     return NULL;
     418              : }
     419              : 
     420              : /* Set value of KEY within this object to a JSON
     421              :    string value based on UTF8_VALUE.
     422              :    Return a borrowed ptr to the new json::string.  */
     423              : 
     424              : const json::string *
     425      1354030 : object::set_string (const char *key, const char *utf8_value)
     426              : {
     427      1354030 :   json::string *str = new json::string (utf8_value);
     428      1354030 :   set (key, str);
     429      1354030 :   return str;
     430              : }
     431              : 
     432              : /* Set value of KEY within this object to a JSON
     433              :    integer value based on V.
     434              :    Return a borrowed ptr to the new json::integer_number.  */
     435              : 
     436              : const json::integer_number *
     437       677110 : object::set_integer (const char *key, long v)
     438              : {
     439       677110 :   json::integer_number *js_int = new json::integer_number (v);
     440       677110 :   set (key, js_int);
     441       677110 :   return js_int;
     442              : }
     443              : 
     444              : /* Set value of KEY within this object to a JSON
     445              :    floating point value based on V.  */
     446              : 
     447              : void
     448           16 : object::set_float (const char *key, double v)
     449              : {
     450           16 :   set (key, new json::float_number (v));
     451           16 : }
     452              : 
     453              : /* Set value of KEY within this object to the JSON
     454              :    literal true or false, based on V.  */
     455              : 
     456              : void
     457          489 : object::set_bool (const char *key, bool v)
     458              : {
     459          978 :   set (key, new json::literal (v));
     460          489 : }
     461              : 
     462              : void
     463          180 : object::set_string (const string_property &property, const char *utf8_value)
     464              : {
     465          180 :   set_string (property.m_key.get (), utf8_value);
     466          180 : }
     467              : 
     468              : void
     469          240 : object::set_integer (const integer_property &property, long value)
     470              : {
     471          240 :   set_integer (property.m_key.get (), value);
     472          240 : }
     473              : 
     474              : void
     475            0 : object::set_bool (const bool_property &property, bool value)
     476              : {
     477            0 :   set_bool (property.m_key.get (), value);
     478            0 : }
     479              : 
     480              : void
     481          780 : object::set_array_of_string (const array_of_string_property &property,
     482              :                              std::unique_ptr<json::array> value)
     483              : {
     484          780 :   set<array> (property.m_key.get (), std::move (value));
     485          780 : }
     486              : 
     487              : /* Subroutine of json::compare for comparing a pairs of objects.  */
     488              : 
     489              : int
     490         5402 : object::compare (const json::object &obj_a, const json::object &obj_b)
     491              : {
     492        16130 :   if (int cmp_size = (int)obj_a.m_keys.length () - (int)obj_b.m_keys.length ())
     493              :     return cmp_size;
     494              : 
     495        18171 :   for (auto iter_a : obj_a.m_map)
     496              :     {
     497        11108 :       const char *key = iter_a.first;
     498        11108 :       const value *value_a = iter_a.second;
     499        11108 :       gcc_assert (value_a);
     500              : 
     501        11108 :       const value *value_b = obj_b.get (key);
     502        11108 :       if (!value_b)
     503              :         /* Key is in OBJ_A but not in OBJ_B.  */
     504         4623 :         return 1;
     505              :       /* If key is OBJ_B but not in OBJ_A, then the
     506              :          count of keys will have been different, or
     507              :          OBJ_A would have had a key not in OBJ_B.  */
     508        11108 :       if (int cmp_value = value::compare (*value_a, *value_b))
     509              :         /* Values for key are non-equal.  */
     510              :         return cmp_value;
     511              :     }
     512              : 
     513              :   /* Objects are equal.  */
     514          578 :   return 0;
     515              : }
     516              : 
     517              : /* class json::array, a subclass of json::value, representing
     518              :    an ordered collection of values.  */
     519              : 
     520              : /* json::array's dtor.  */
     521              : 
     522      1247136 : array::~array ()
     523              : {
     524       624015 :   unsigned i;
     525       624015 :   value *v;
     526      1421757 :   FOR_EACH_VEC_ELT (m_elements, i, v)
     527       797742 :     delete v;
     528      1247136 : }
     529              : 
     530              : /* Implementation of json::value::print for json::array.  */
     531              : 
     532              : void
     533        92958 : array::print (pretty_printer *pp, bool formatted) const
     534              : {
     535        92958 :   pp_character (pp, '[');
     536        92958 :   if (formatted)
     537         3019 :     pp_indentation (pp) += 1;
     538              :   unsigned i;
     539              :   value *v;
     540       298317 :   FOR_EACH_VEC_ELT (m_elements, i, v)
     541              :     {
     542       205359 :       if (i)
     543              :         {
     544       127480 :           pp_string (pp, ",");
     545       127480 :           if (formatted)
     546              :             {
     547         6668 :               pp_newline (pp);
     548         6668 :               pp_indent (pp);
     549              :             }
     550              :           else
     551       120812 :             pp_space (pp);
     552              :         }
     553       205359 :       v->print (pp, formatted);
     554              :     }
     555        92958 :   if (formatted)
     556         3019 :     pp_indentation (pp) -= 1;
     557        92958 :   pp_character (pp, ']');
     558        92958 : }
     559              : 
     560              : std::unique_ptr<value>
     561          664 : array::clone () const
     562              : {
     563          664 :   auto result = std::make_unique<array> ();
     564          664 :   unsigned i;
     565          664 :   value *v;
     566         2301 :   FOR_EACH_VEC_ELT (m_elements, i, v)
     567          973 :     result->append (v->clone ());
     568          664 :   return result;
     569          664 : }
     570              : 
     571              : /* Append non-NULL value V to a json::array, taking ownership of V.  */
     572              : 
     573              : void
     574       797821 : array::append (value *v)
     575              : {
     576       797821 :   gcc_assert (v);
     577      1400061 :   v->m_pointer_token = pointer::token (*this, m_elements.length ());
     578       797821 :   m_elements.safe_push (v);
     579       797821 : }
     580              : 
     581              : /* Append UTF8_VALUE to this array, returning a borrowed pointer to the
     582              :    new json::string.  */
     583              : 
     584              : const json::string *
     585       176935 : array::append_string (const char *utf8_value)
     586              : {
     587       176935 :   gcc_assert (utf8_value);
     588       176935 :   auto js_str = new json::string (utf8_value);
     589       176935 :   append (js_str);
     590       176935 :   return js_str;
     591              : }
     592              : 
     593              : /* class json::float_number, a subclass of json::value, wrapping a double.  */
     594              : 
     595              : /* Implementation of json::value::print for json::float_number.  */
     596              : 
     597              : void
     598           32 : float_number::print (pretty_printer *pp,
     599              :                      bool formatted ATTRIBUTE_UNUSED) const
     600              : {
     601           32 :   char tmp[1024];
     602           32 :   snprintf (tmp, sizeof (tmp), "%g", m_value);
     603           32 :   pp_string (pp, tmp);
     604           32 : }
     605              : 
     606              : std::unique_ptr<value>
     607            4 : float_number::clone () const
     608              : {
     609            4 :   return std::make_unique<float_number> (m_value);
     610              : }
     611              : 
     612              : /* class json::integer_number, a subclass of json::value, wrapping a long.  */
     613              : 
     614              : /* Implementation of json::value::print for json::integer_number.  */
     615              : 
     616              : void
     617       173077 : integer_number::print (pretty_printer *pp,
     618              :                        bool formatted ATTRIBUTE_UNUSED) const
     619              : {
     620       173077 :   char tmp[1024];
     621       173077 :   snprintf (tmp, sizeof (tmp), "%ld", m_value);
     622       173077 :   pp_string (pp, tmp);
     623       173077 : }
     624              : 
     625              : std::unique_ptr<value>
     626          217 : integer_number::clone () const
     627              : {
     628          217 :   return std::make_unique<integer_number> (m_value);
     629              : }
     630              : 
     631              : /* class json::string, a subclass of json::value.  */
     632              : 
     633              : /* json::string's ctor.  */
     634              : 
     635      2082012 : string::string (const char *utf8)
     636              : {
     637      2082012 :   gcc_assert (utf8);
     638      2082012 :   m_utf8 = xstrdup (utf8);
     639      2082012 :   m_len = strlen (utf8);
     640      2082012 : }
     641              : 
     642         3434 : string::string (const char *utf8, size_t len)
     643              : {
     644         3434 :   gcc_assert (utf8);
     645         3434 :   m_utf8 = XNEWVEC (char, len + 1);
     646         3434 :   m_len = len;
     647         3434 :   memcpy (m_utf8, utf8, len);
     648         3434 :   m_utf8[len] = '\0';
     649         3434 : }
     650              : 
     651              : /* Implementation of json::value::print for json::string.  */
     652              : 
     653              : void
     654       491086 : string::print (pretty_printer *pp,
     655              :                bool formatted ATTRIBUTE_UNUSED) const
     656              : {
     657       491086 :   print_escaped_json_string (pp, m_utf8, m_len);
     658       491086 : }
     659              : 
     660              : std::unique_ptr<value>
     661         3197 : string::clone () const
     662              : {
     663         3197 :   return std::make_unique<string> (m_utf8, m_len);
     664              : }
     665              : 
     666              : /* class json::literal, a subclass of json::value.  */
     667              : 
     668              : /* Implementation of json::value::print for json::literal.  */
     669              : 
     670              : void
     671          225 : literal::print (pretty_printer *pp,
     672              :                 bool formatted ATTRIBUTE_UNUSED) const
     673              : {
     674          225 :   switch (m_kind)
     675              :     {
     676          125 :     case JSON_TRUE:
     677          125 :       pp_string (pp, "true");
     678          125 :       break;
     679           92 :     case JSON_FALSE:
     680           92 :       pp_string (pp, "false");
     681           92 :       break;
     682            8 :     case JSON_NULL:
     683            8 :       pp_string (pp, "null");
     684            8 :       break;
     685            0 :     default:
     686            0 :       gcc_unreachable ();
     687              :     }
     688          225 : }
     689              : 
     690              : std::unique_ptr<value>
     691            4 : literal::clone () const
     692              : {
     693            4 :   return std::make_unique<literal> (m_kind);
     694              : }
     695              : 
     696              : 
     697              : #if CHECKING_P
     698              : 
     699              : namespace selftest {
     700              : 
     701              : /* Selftests.  */
     702              : 
     703              : /* Verify that JV->print () prints EXPECTED_JSON.  */
     704              : 
     705              : void
     706          160 : assert_print_eq (const location &loc,
     707              :                  const json::value &jv,
     708              :                  bool formatted,
     709              :                  const char *expected_json)
     710              : {
     711          160 :   pretty_printer pp;
     712          160 :   jv.print (&pp, formatted);
     713          160 :   ASSERT_STREQ_AT (loc, expected_json, pp_formatted_text (&pp));
     714          160 : }
     715              : 
     716              : #define ASSERT_PRINT_EQ(JV, FORMATTED, EXPECTED_JSON)   \
     717              :   assert_print_eq (SELFTEST_LOCATION, JV, FORMATTED, EXPECTED_JSON)
     718              : 
     719              : /* Verify that object::get works as expected.  */
     720              : 
     721              : static void
     722            4 : test_object_get ()
     723              : {
     724            4 :   object obj;
     725            4 :   value *val = new json::string ("value");
     726            4 :   obj.set ("foo", val);
     727            4 :   ASSERT_EQ (obj.get ("foo"), val);
     728            4 :   ASSERT_EQ (obj.get ("not-present"), NULL);
     729            4 : }
     730              : 
     731              : /* Verify that JSON objects are written correctly.  */
     732              : 
     733              : static void
     734            4 : test_writing_objects ()
     735              : {
     736            4 :   object obj;
     737            4 :   obj.set_string ("foo", "bar");
     738            4 :   obj.set_string ("baz", "quux");
     739            4 :   obj.set_string ("\"\\\b\f\n\r\t", "value for awkward key");
     740              : 
     741              :   /* This test relies on json::object writing out key/value pairs
     742              :      in key-insertion order.  */
     743            4 :   ASSERT_PRINT_EQ (obj, true,
     744              :                    "{\"foo\": \"bar\",\n"
     745              :                    " \"baz\": \"quux\",\n"
     746              :                    " \"\\\"\\\\\\b\\f\\n\\r\\t\": \"value for awkward key\"}");
     747            4 :   ASSERT_PRINT_EQ (obj, false,
     748              :                    "{\"foo\": \"bar\", \"baz\": \"quux\""
     749              :                    ", \"\\\"\\\\\\b\\f\\n\\r\\t\": \"value for awkward key\"}");
     750            4 : }
     751              : 
     752              : /* Verify that JSON arrays are written correctly.  */
     753              : 
     754              : static void
     755            4 : test_writing_arrays ()
     756              : {
     757            4 :   array arr;
     758            4 :   ASSERT_PRINT_EQ (arr, true, "[]");
     759              : 
     760            4 :   arr.append (new json::string ("foo"));
     761            4 :   ASSERT_PRINT_EQ (arr, true, "[\"foo\"]");
     762              : 
     763            4 :   arr.append_string ("bar");
     764            4 :   ASSERT_PRINT_EQ (arr, true,
     765              :                    "[\"foo\",\n"
     766              :                    " \"bar\"]");
     767            4 :   ASSERT_PRINT_EQ (arr, false,
     768              :                    "[\"foo\", \"bar\"]");
     769            4 : }
     770              : 
     771              : /* Verify that JSON numbers are written correctly.  */
     772              : 
     773              : static void
     774            4 : test_writing_float_numbers ()
     775              : {
     776            4 :   ASSERT_PRINT_EQ (float_number (0), true, "0");
     777            4 :   ASSERT_PRINT_EQ (float_number (42), true, "42");
     778            4 :   ASSERT_PRINT_EQ (float_number (-100), true, "-100");
     779            4 :   ASSERT_PRINT_EQ (float_number (123456789), true, "1.23457e+08");
     780            4 : }
     781              : 
     782              : static void
     783            4 : test_writing_integer_numbers ()
     784              : {
     785            4 :   ASSERT_PRINT_EQ (integer_number (0), true, "0");
     786            4 :   ASSERT_PRINT_EQ (integer_number (42), true, "42");
     787            4 :   ASSERT_PRINT_EQ (integer_number (-100), true, "-100");
     788            4 :   ASSERT_PRINT_EQ (integer_number (123456789), true, "123456789");
     789            4 :   ASSERT_PRINT_EQ (integer_number (-123456789), true, "-123456789");
     790            4 : }
     791              : 
     792              : /* Verify that JSON strings are written correctly.  */
     793              : 
     794              : static void
     795            4 : test_writing_strings ()
     796              : {
     797            4 :   string foo ("foo");
     798            4 :   ASSERT_PRINT_EQ (foo, true, "\"foo\"");
     799              : 
     800            4 :   string contains_quotes ("before \"quoted\" after");
     801            4 :   ASSERT_PRINT_EQ (contains_quotes, true, "\"before \\\"quoted\\\" after\"");
     802              : 
     803            4 :   const char data[] = {'a', 'b', 'c', 'd', '\0', 'e', 'f'};
     804            4 :   string not_terminated (data, 3);
     805            4 :   ASSERT_PRINT_EQ (not_terminated, true, "\"abc\"");
     806            4 :   string embedded_null (data, sizeof data);
     807            4 :   ASSERT_PRINT_EQ (embedded_null, true, "\"abcd\\0ef\"");
     808            4 : }
     809              : 
     810              : /* Verify that JSON literals are written correctly.  */
     811              : 
     812              : static void
     813            4 : test_writing_literals ()
     814              : {
     815            4 :   ASSERT_PRINT_EQ (literal (JSON_TRUE), true, "true");
     816            4 :   ASSERT_PRINT_EQ (literal (JSON_FALSE), true, "false");
     817            4 :   ASSERT_PRINT_EQ (literal (JSON_NULL), true, "null");
     818              : 
     819            4 :   ASSERT_PRINT_EQ (literal (true), true, "true");
     820            4 :   ASSERT_PRINT_EQ (literal (false), true, "false");
     821            4 : }
     822              : 
     823              : /* Verify that nested values are formatted correctly when written.
     824              : 
     825              :    Also, make use of array::append(std::unique_ptr<value>) and
     826              :    object::set (const char *key, std::unique_ptr<value> v).*/
     827              : 
     828              : static void
     829            4 : test_formatting ()
     830              : {
     831            4 :   object obj;
     832            4 :   object *child = new object;
     833            4 :   std::unique_ptr<object> grandchild = std::make_unique<object> ();
     834              : 
     835            4 :   obj.set_string ("str", "bar");
     836            4 :   obj.set ("child", child);
     837            4 :   obj.set_integer ("int", 42);
     838              : 
     839            4 :   array *arr = new array;
     840           16 :   for (int i = 0; i < 3; i++)
     841           12 :     arr->append (std::make_unique<integer_number> (i));
     842            4 :   grandchild->set ("arr", arr);
     843            4 :   grandchild->set_integer ("int", 1066);
     844              : 
     845            4 :   child->set ("grandchild", std::move (grandchild));
     846            4 :   child->set_integer ("int", 1776);
     847              : 
     848              :   /* This test relies on json::object writing out key/value pairs
     849              :      in key-insertion order.  */
     850            4 :   ASSERT_PRINT_EQ (obj, true,
     851              :                    ("{\"str\": \"bar\",\n"
     852              :                     " \"child\": {\"grandchild\": {\"arr\": [0,\n"
     853              :                     "                                  1,\n"
     854              :                     "                                  2],\n"
     855              :                     "                          \"int\": 1066},\n"
     856              :                     "           \"int\": 1776},\n"
     857              :                     " \"int\": 42}"));
     858            4 :   ASSERT_PRINT_EQ (obj, false,
     859              :                    ("{\"str\": \"bar\", \"child\": {\"grandchild\":"
     860              :                     " {\"arr\": [0, 1, 2], \"int\": 1066},"
     861              :                     " \"int\": 1776}, \"int\": 42}"));
     862            4 : }
     863              : 
     864              : /* Helper function for reporting failure of JSON comparisons.  */
     865              : 
     866              : static void
     867            0 : fail_comparison (const location &loc,
     868              :                  const char *desc,
     869              :                  const value &val_a, const value &val_b,
     870              :                  const char *desc_expected_value,
     871              :                  int actual_value)
     872              : {
     873            0 :   fprintf (stderr, "val_a: ");
     874            0 :   val_a.dump ();
     875              : 
     876            0 :   fprintf (stderr, "val_b: ");
     877            0 :   val_b.dump ();
     878              : 
     879            0 :   selftest::fail_formatted (loc,
     880              :                             "%s: failed JSON comparison:"
     881              :                             " expected: %s got: %i\n",
     882              :                             desc,
     883              :                             desc_expected_value, actual_value);
     884              : }
     885              : 
     886              : /* Implementation of ASSERT_JSON_EQ.  */
     887              : 
     888              : static void
     889          100 : assert_json_equal (const location &loc,
     890              :                    const char *desc,
     891              :                    const value &val_a, const value &val_b)
     892              : {
     893              :   /* Comparison should return zero, both ways, indicating no differences.  */
     894          100 :   const int a_vs_b = value::compare (val_a, val_b);
     895          100 :   if (a_vs_b != 0)
     896            0 :     fail_comparison (loc, desc, val_a, val_b, "zero", a_vs_b);
     897              : 
     898          100 :   const int b_vs_a = value::compare (val_b, val_a);
     899          100 :   if (b_vs_a != 0)
     900            0 :     fail_comparison (loc, desc, val_b, val_a, "zero", b_vs_a);
     901          100 : }
     902              : 
     903              : /* Verify that json::value::compare returns 0 ("no differences") on
     904              :    VAL1 and VAL2, in both orders.  */
     905              : 
     906              : #define ASSERT_JSON_EQ(VAL1, VAL2) \
     907              :   SELFTEST_BEGIN_STMT                                           \
     908              :     assert_json_equal ((SELFTEST_LOCATION),                     \
     909              :                        "ASSERT_JSON_EQ",                      \
     910              :                        (VAL1), (VAL2));                 \
     911              :   SELFTEST_END_STMT
     912              : 
     913              : /* Implementation of ASSERT_JSON_NE.  */
     914              : 
     915              : static void
     916           48 : assert_json_non_equal (const location &loc,
     917              :                        const char *desc,
     918              :                        const value &val_a, const value &val_b)
     919              : {
     920              :   /* Comparison should be non-zero, indicating differences.  */
     921           48 :   const int a_vs_b = value::compare (val_a, val_b);
     922           48 :   if (a_vs_b == 0)
     923            0 :     fail_comparison (loc, desc, val_a, val_b, "non-zero", a_vs_b);
     924              : 
     925           48 :   const int b_vs_a = value::compare (val_b, val_a);
     926           48 :   ASSERT_NE_AT (loc, b_vs_a, 0);
     927           48 :   if (b_vs_a == 0)
     928              :     fail_comparison (loc, desc, val_b, val_a, "non-zero", b_vs_a);
     929              : 
     930              :   /* Swapping the args should swap the sign of the result
     931              :      (but isn't necessarily the negation).  */
     932           48 :   if ( (a_vs_b > 0) == (b_vs_a > 0) )
     933            0 :     fail_comparison (loc, desc, val_b, val_a, "opposite signs", 1);
     934           48 : }
     935              : 
     936              : /* Verify that json::value::compare returns non-zero ("different") on
     937              :    VAL1 and VAL2, in both orders, and that they have opposite
     938              :    sign.  */
     939              : 
     940              : #define ASSERT_JSON_NE(VAL1, VAL2) \
     941              :   SELFTEST_BEGIN_STMT                                           \
     942              :     assert_json_non_equal ((SELFTEST_LOCATION),         \
     943              :                            "ASSERT_JSON_NE",                  \
     944              :                            (VAL1), (VAL2));                     \
     945              :   SELFTEST_END_STMT
     946              : 
     947              : /* Verify that json::value::compare works as expected.  */
     948              : 
     949              : static void
     950            4 : test_comparisons ()
     951              : {
     952              :   /* Literals.  */
     953              : 
     954            4 :   literal null_lit (JSON_NULL);
     955            4 :   ASSERT_JSON_EQ (null_lit, null_lit);
     956              : 
     957            4 :   literal other_null_lit (JSON_NULL);
     958            4 :   ASSERT_JSON_EQ (null_lit, other_null_lit);
     959              : 
     960            4 :   literal true_lit (JSON_TRUE);
     961            4 :   ASSERT_JSON_EQ (true_lit, true_lit);
     962            4 :   ASSERT_JSON_NE (true_lit, null_lit);
     963              : 
     964            4 :   literal false_lit (JSON_FALSE);
     965            4 :   ASSERT_JSON_EQ (false_lit, false_lit);
     966            4 :   ASSERT_JSON_NE (false_lit, true_lit);
     967            4 :   ASSERT_JSON_NE (false_lit, null_lit);
     968              : 
     969              :   /* Strings.  */
     970            4 :   string str_foo_1 ("foo");
     971            4 :   ASSERT_JSON_EQ (str_foo_1, str_foo_1);
     972              : 
     973            4 :   string str_foo_2 ("foo");
     974            4 :   ASSERT_JSON_EQ (str_foo_1, str_foo_2);
     975              : 
     976            4 :   string str_bar ("bar");
     977            4 :   ASSERT_JSON_NE (str_bar, str_foo_1);
     978              : 
     979              :   /* Numbers.  */
     980            4 :   integer_number i_42 (42);
     981            4 :   ASSERT_JSON_EQ (i_42, i_42);
     982            4 :   integer_number i_42_2 (42);
     983            4 :   ASSERT_JSON_EQ (i_42, i_42_2);
     984            4 :   integer_number i_43 (43);
     985            4 :   ASSERT_JSON_NE (i_42, i_43);
     986              : 
     987            4 :   float_number f_zero (0.0);
     988            4 :   ASSERT_JSON_EQ (f_zero, f_zero);
     989            4 :   float_number f_zero_2 (0.0);
     990            4 :   ASSERT_JSON_EQ (f_zero, f_zero_2);
     991            4 :   float_number f_one (1.0);
     992            4 :   ASSERT_JSON_NE (f_zero, f_one);
     993              :   /* We don't yet test the more awkward cases e.g. NaN.  */
     994              : 
     995              :   /* Objects.  */
     996              : 
     997              :   // Empty object
     998              :   // Self comparison should be 0
     999            4 :   object empty_obj_a;
    1000            4 :   ASSERT_JSON_EQ (empty_obj_a, empty_obj_a);
    1001              : 
    1002              :   // Instances of empty objects should compare equal to each other
    1003            4 :   object empty_obj_b;
    1004            4 :   ASSERT_JSON_EQ (empty_obj_a, empty_obj_b);
    1005              : 
    1006              :   // Object with one field:
    1007            4 :   object obj_1;
    1008            4 :   obj_1.set_string ("foo", "bar");
    1009              :   // Self comparison should be 0
    1010            4 :   ASSERT_JSON_EQ (obj_1, obj_1);
    1011              : 
    1012              :   // but should be different to an empty object:
    1013            4 :   ASSERT_JSON_NE (obj_1, empty_obj_a);
    1014              : 
    1015              :   // Another with one field, with same key/value:
    1016            4 :   object obj_2;
    1017            4 :   obj_2.set_string ("foo", "bar");
    1018            4 :   ASSERT_JSON_EQ (obj_1, obj_2);
    1019              : 
    1020              :   // Same key, different value:
    1021            4 :   object obj_3;
    1022            4 :   obj_3.set_string ("foo", "baz");
    1023            4 :   ASSERT_JSON_NE (obj_1, obj_3);
    1024              : 
    1025              :   // Adding an extra property:
    1026            4 :   obj_2.set_integer ("year", 1066);
    1027            4 :   ASSERT_JSON_NE (obj_1, obj_2);
    1028              : 
    1029              :   /* Different insertion order, but same k-v pairs should be equal,
    1030              :      despite having different serialization.  */
    1031            4 :   object obj_4;
    1032            4 :   obj_4.set_integer ("year", 1066);
    1033            4 :   obj_4.set_string ("foo", "bar");
    1034            4 :   ASSERT_JSON_EQ (obj_2, obj_4);
    1035            4 :   ASSERT_PRINT_EQ (obj_2, false, "{\"foo\": \"bar\", \"year\": 1066}");
    1036            4 :   ASSERT_PRINT_EQ (obj_4, false, "{\"year\": 1066, \"foo\": \"bar\"}");
    1037              : 
    1038              :   /* Arrays.  */
    1039              : 
    1040              :   // Empty array
    1041            4 :   array empty_arr_a;
    1042              :   // Self comparison should be 0
    1043            4 :   ASSERT_JSON_EQ (empty_arr_a, empty_arr_a);
    1044              : 
    1045              :   // Objects and arrays are different
    1046            4 :   ASSERT_JSON_NE (empty_obj_a, empty_arr_a);
    1047              : 
    1048              :   // Instances of empty arrays should compare equal to each other
    1049            4 :   array empty_arr_b;
    1050            4 :   ASSERT_JSON_EQ (empty_arr_a, empty_arr_b);
    1051              : 
    1052              :   // Array with one element:
    1053            4 :   array arr_1;
    1054            4 :   arr_1.append (std::make_unique<string> ("foo"));
    1055              :   // Self comparison should be 0
    1056            4 :   ASSERT_JSON_EQ (arr_1, arr_1);
    1057              : 
    1058              :   // but should be different to an empty array:
    1059            4 :   ASSERT_JSON_NE (arr_1, empty_arr_a);
    1060              : 
    1061              :   // Another with one element:
    1062            4 :   array arr_2;
    1063            4 :   arr_2.append (std::make_unique<string> ("foo"));
    1064            4 :   ASSERT_JSON_EQ (arr_1, arr_2);
    1065              : 
    1066              :   // Adding an extra element:
    1067            4 :   arr_2.append (std::make_unique<string> ("bar"));
    1068            4 :   ASSERT_JSON_NE (arr_1, arr_2);
    1069            4 : }
    1070              : 
    1071              : /* Ensure that json::string's get_string is usable as a C-style string.  */
    1072              : 
    1073              : static void
    1074            4 : test_strcmp ()
    1075              : {
    1076            4 :   string str ("foobar", 3);
    1077            4 :   ASSERT_EQ (strcmp (str.get_string (), "foo"), 0);
    1078            4 : }
    1079              : 
    1080              : static void
    1081            4 : test_cloning ()
    1082              : {
    1083              :   // Objects
    1084            4 :   {
    1085            4 :     object obj;
    1086            4 :     obj.set_string ("foo", "bar");
    1087              : 
    1088            4 :     auto obj_clone = obj.clone ();
    1089            4 :     ASSERT_JSON_EQ (obj, *obj_clone);
    1090            4 :   }
    1091              : 
    1092              :   // Arrays
    1093            4 :   {
    1094            4 :     array arr;
    1095            4 :     arr.append (std::make_unique<string> ("foo"));
    1096              : 
    1097            4 :     auto arr_clone = arr.clone ();
    1098            4 :     ASSERT_JSON_EQ (arr, *arr_clone);
    1099            4 :   }
    1100              : 
    1101              :   // float_number
    1102            4 :   {
    1103            4 :     float_number f_one (1.0);
    1104            4 :     auto f_clone = f_one.clone ();
    1105            4 :     ASSERT_JSON_EQ (f_one, *f_clone);
    1106            4 :   }
    1107              : 
    1108              :   // integer_number
    1109            4 :   {
    1110            4 :     integer_number num (42);
    1111            4 :     auto num_clone = num.clone ();
    1112            4 :     ASSERT_JSON_EQ (num, *num_clone);
    1113            4 :   }
    1114              : 
    1115              :   // string
    1116            4 :   {
    1117            4 :     string str ("foo");
    1118            4 :     auto str_clone = str.clone ();
    1119            4 :     ASSERT_JSON_EQ (str, *str_clone);
    1120            4 :   }
    1121              : 
    1122              :   // literal
    1123            4 :   {
    1124            4 :     literal lit (JSON_TRUE);
    1125            4 :     auto lit_clone = lit.clone ();
    1126            4 :     ASSERT_JSON_EQ (lit, *lit_clone);
    1127            4 :   }
    1128            4 : }
    1129              : 
    1130              : /* Run all of the selftests within this file.  */
    1131              : 
    1132              : void
    1133            4 : json_cc_tests ()
    1134              : {
    1135            4 :   test_object_get ();
    1136            4 :   test_writing_objects ();
    1137            4 :   test_writing_arrays ();
    1138            4 :   test_writing_float_numbers ();
    1139            4 :   test_writing_integer_numbers ();
    1140            4 :   test_writing_strings ();
    1141            4 :   test_writing_literals ();
    1142            4 :   test_formatting ();
    1143            4 :   test_comparisons ();
    1144            4 :   test_strcmp ();
    1145            4 :   test_cloning ();
    1146            4 : }
    1147              : 
    1148              : } // namespace selftest
    1149              : 
    1150              : #endif /* #if CHECKING_P */
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.