LCOV - code coverage report
Current view: top level - gcc - pretty-print-token-buffer.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 63.1 % 195 123
Test Date: 2026-05-11 19:44:49 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Capturing the results of pretty_print for later playback.
       2              :    Copyright (C) 2023-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              : #define INCLUDE_STRING
      23              : #include "system.h"
      24              : #include "coretypes.h"
      25              : #include "intl.h"
      26              : #include "pretty-print.h"
      27              : #include "pretty-print-token-buffer.h"
      28              : #include "selftest.h"
      29              : 
      30              : /* A token_printer that makes a deep copy of the pp_token_list
      31              :    into another obstack.  */
      32              : 
      33           56 : class copying_token_printer : public token_printer
      34              : {
      35              : public:
      36           56 :   copying_token_printer (obstack &dst_obstack,
      37              :                          pp_token_list &dst_token_list)
      38           56 :   : m_dst_obstack (dst_obstack),
      39           56 :     m_dst_token_list (dst_token_list)
      40              :   {
      41              :   }
      42              : 
      43              :   void
      44           56 :   print_tokens (pretty_printer *,
      45              :                 const pp_token_list &tokens) final override
      46              :   {
      47          488 :     for (auto iter = tokens.m_first; iter; iter = iter->m_next)
      48          432 :       switch (iter->m_kind)
      49              :         {
      50            0 :         default:
      51            0 :           gcc_unreachable ();
      52              : 
      53          208 :         case pp_token::kind::text:
      54          208 :           {
      55          208 :             const pp_token_text *sub = as_a <const pp_token_text *> (iter);
      56              :             /* Copy the text, with null terminator.  */
      57          208 :             obstack_grow (&m_dst_obstack, sub->m_value.get (),
      58              :                           strlen (sub->m_value.get ()) + 1);
      59          208 :             m_dst_token_list.push_back_text
      60          208 :               (label_text::borrow (XOBFINISH (&m_dst_obstack,
      61              :                                               const char *)));
      62              :           }
      63          208 :           break;
      64              : 
      65            0 :         case pp_token::kind::begin_color:
      66            0 :           {
      67            0 :             pp_token_begin_color *sub = as_a <pp_token_begin_color *> (iter);
      68              :             /* Copy the color, with null terminator.  */
      69            0 :             obstack_grow (&m_dst_obstack, sub->m_value.get (),
      70              :                           strlen (sub->m_value.get ()) + 1);
      71            0 :             m_dst_token_list.push_back<pp_token_begin_color>
      72            0 :               (label_text::borrow (XOBFINISH (&m_dst_obstack,
      73              :                                               const char *)));
      74              :           }
      75            0 :           break;
      76            0 :         case pp_token::kind::end_color:
      77            0 :           m_dst_token_list.push_back<pp_token_end_color> ();
      78            0 :           break;
      79              : 
      80          112 :         case pp_token::kind::begin_quote:
      81          112 :           m_dst_token_list.push_back<pp_token_begin_quote> ();
      82          112 :           break;
      83          112 :         case pp_token::kind::end_quote:
      84          112 :           m_dst_token_list.push_back<pp_token_end_quote> ();
      85          112 :           break;
      86              : 
      87            0 :         case pp_token::kind::begin_url:
      88            0 :           {
      89            0 :             pp_token_begin_url *sub = as_a <pp_token_begin_url *> (iter);
      90              :             /* Copy the URL, with null terminator.  */
      91            0 :             obstack_grow (&m_dst_obstack, sub->m_value.get (),
      92              :                           strlen (sub->m_value.get ()) + 1);
      93            0 :             m_dst_token_list.push_back<pp_token_begin_url>
      94            0 :               (label_text::borrow (XOBFINISH (&m_dst_obstack,
      95              :                                               const char *)));
      96              :           }
      97            0 :           break;
      98            0 :         case pp_token::kind::end_url:
      99            0 :           m_dst_token_list.push_back<pp_token_end_url> ();
     100            0 :           break;
     101              : 
     102            0 :         case pp_token::kind::event_id:
     103            0 :           {
     104            0 :             pp_token_event_id *sub = as_a <pp_token_event_id *> (iter);
     105            0 :             m_dst_token_list.push_back<pp_token_event_id> (sub->m_event_id);
     106              :           }
     107            0 :           break;
     108              : 
     109            0 :         case pp_token::kind::custom_data:
     110              :           /* These should have been eliminated by replace_custom_tokens.  */
     111            0 :           gcc_unreachable ();
     112          432 :           break;
     113              :         }
     114           56 :   }
     115              : 
     116              : private:
     117              :   obstack &m_dst_obstack;
     118              :   pp_token_list &m_dst_token_list;
     119              : };
     120              : 
     121            4 : pretty_print_token_buffer::pretty_print_token_buffer ()
     122            4 : : m_obstack (std::make_unique<auto_obstack> ()),
     123            4 :   m_tokens (*m_obstack.get ())
     124              : {
     125            4 : }
     126              : 
     127              : /* Capture GMSGID and ARGS as a sequence of pretty_print tokens.  */
     128              : 
     129           56 : pretty_print_token_buffer::pretty_print_token_buffer (const char *gmsgid,
     130           56 :                                                       va_list *args)
     131           56 : : m_obstack (std::make_unique<auto_obstack> ()),
     132           56 :   m_tokens (*m_obstack.get ())
     133              : {
     134           56 :   text_info text (gmsgid, args, errno);
     135           56 :   pretty_printer pp;
     136           56 :   pp.set_output_stream (nullptr);
     137           56 :   copying_token_printer tok_printer (*m_obstack.get (), m_tokens);
     138           56 :   pp.set_token_printer (&tok_printer);
     139           56 :   pp_format (&pp, &text);
     140           56 :   pp_output_formatted_text (&pp, nullptr);
     141           56 : }
     142              : 
     143          104 : pretty_print_token_buffer::
     144          104 : pretty_print_token_buffer (pretty_print_token_buffer &&other)
     145          104 : : m_obstack (std::move (other.m_obstack)),
     146          104 :   m_tokens (std::move (other.m_tokens))
     147              : {
     148          104 : }
     149              : 
     150              : /* Convert to text, dropping colorization, URLs, etc.  */
     151              : 
     152              : std::string
     153           52 : pretty_print_token_buffer::to_string () const
     154              : {
     155           52 :   std::string result;
     156              : 
     157          452 :   for (auto iter = m_tokens.m_first; iter; iter = iter->m_next)
     158          400 :     switch (iter->m_kind)
     159              :       {
     160            0 :       default:
     161            0 :         gcc_unreachable ();
     162              : 
     163          192 :       case pp_token::kind::text:
     164          192 :         {
     165          192 :           pp_token_text *sub = as_a <pp_token_text *> (iter);
     166          192 :           result += sub->m_value.get ();
     167              :         }
     168          192 :         break;
     169              : 
     170              :       case pp_token::kind::begin_color:
     171              :       case pp_token::kind::end_color:
     172              :         // Skip
     173              :         break;
     174              : 
     175          104 :       case pp_token::kind::begin_quote:
     176          104 :         result += open_quote;
     177          104 :         break;
     178              : 
     179          104 :       case pp_token::kind::end_quote:
     180          104 :         result += close_quote;
     181          104 :         break;
     182              : 
     183              :       case pp_token::kind::begin_url:
     184              :       case pp_token::kind::end_url:
     185              :         // Skip
     186              :         break;
     187              : 
     188            0 :       case pp_token::kind::event_id:
     189            0 :         {
     190            0 :           pp_token_event_id *sub = as_a <pp_token_event_id *> (iter);
     191            0 :           gcc_assert (sub->m_event_id.known_p ());
     192            0 :           result += '(';
     193            0 :           result += std::to_string (sub->m_event_id.one_based ());
     194            0 :           result += ')';
     195              :         }
     196            0 :         break;
     197              : 
     198            0 :       case pp_token::kind::custom_data:
     199              :         /* We don't have a way of handling custom_data tokens here.  */
     200            0 :         gcc_unreachable ();
     201          400 :         break;
     202              :       }
     203              : 
     204           52 :   return result;
     205              : }
     206              : 
     207              : // class pp_token_buffer_element : public pp_element
     208              : 
     209              : void
     210            8 : pp_token_buffer_element::add_to_phase_2 (pp_markup::context &ctxt)
     211              : {
     212           40 :   for (auto iter = m_token_buf.m_tokens.m_first; iter; iter = iter->m_next)
     213           32 :     switch (iter->m_kind)
     214              :       {
     215            0 :       default:
     216            0 :         gcc_unreachable ();
     217              : 
     218           16 :       case pp_token::kind::text:
     219           16 :         {
     220           16 :           const pp_token_text *sub = as_a <const pp_token_text *> (iter);
     221           16 :           pp_string (&ctxt.m_pp, sub->m_value.get ());
     222           16 :           ctxt.push_back_any_text ();
     223              :         }
     224           16 :         break;
     225              : 
     226            0 :       case pp_token::kind::begin_color:
     227            0 :         {
     228            0 :           const pp_token_begin_color *sub
     229            0 :             = as_a <const pp_token_begin_color *> (iter);
     230            0 :           gcc_assert (sub->m_value.get ());
     231            0 :           ctxt.begin_highlight_color (sub->m_value.get ());
     232              :         }
     233            0 :         break;
     234              : 
     235            0 :       case pp_token::kind::end_color:
     236            0 :         ctxt.end_highlight_color ();
     237            0 :         break;
     238              : 
     239            8 :       case pp_token::kind::begin_quote:
     240            8 :         ctxt.begin_quote ();
     241            8 :         break;
     242              : 
     243            8 :       case pp_token::kind::end_quote:
     244            8 :         ctxt.end_quote ();
     245            8 :         break;
     246              : 
     247            0 :       case pp_token::kind::begin_url:
     248            0 :         {
     249            0 :           const pp_token_begin_url *sub
     250            0 :             = as_a <const pp_token_begin_url *> (iter);
     251            0 :           gcc_assert (sub->m_value.get ());
     252            0 :           ctxt.begin_url (sub->m_value.get ());
     253              :         }
     254            0 :         break;
     255              : 
     256            0 :       case pp_token::kind::end_url:
     257            0 :         ctxt.end_url ();
     258            0 :         break;
     259              : 
     260            0 :       case pp_token::kind::event_id:
     261            0 :         {
     262            0 :           const pp_token_event_id *sub
     263            0 :             = as_a <const pp_token_event_id *> (iter);
     264            0 :           gcc_assert (sub->m_event_id.known_p ());
     265            0 :           ctxt.add_event_id (sub->m_event_id);
     266              :         }
     267            0 :         break;
     268              : 
     269            0 :       case pp_token::kind::custom_data:
     270              :         /* We don't have a way of handling custom_data tokens here.  */
     271            0 :         gcc_unreachable ();
     272           32 :         break;
     273              :       }
     274            8 : }
     275              : 
     276              : #if CHECKING_P
     277              : 
     278              : namespace selftest {
     279              : 
     280              : static pretty_print_token_buffer
     281            4 : pp_printf_to_buf (const char *fmt, ...)
     282              : {
     283            4 :   va_list args;
     284            4 :   va_start (args, fmt);
     285              : 
     286            4 :   pretty_print_token_buffer buf (fmt, &args);
     287              : 
     288            4 :   va_end (args);
     289              : 
     290            4 :   return buf;
     291              : }
     292              : 
     293              : static void
     294            4 : test_empty ()
     295              : {
     296            4 :   pretty_print_token_buffer buf;
     297            4 :   pp_token_buffer_element e (buf);
     298            4 :   pretty_printer pp;
     299            4 :   pp_printf (&pp, "before %e after", &e);
     300            4 :   ASSERT_STREQ (pp_formatted_text (&pp), "before  after");
     301            4 : }
     302              : 
     303              : static void
     304            4 : test_print ()
     305              : {
     306            4 :   pretty_print_token_buffer buf
     307            4 :     = pp_printf_to_buf ("x: %qs y: %qs", "foo", "bar");
     308              : 
     309              :   // Check that the individual tokens are captured in "buf".
     310            4 :   pp_token *tok0 = buf.m_tokens.m_first;
     311            4 :   ASSERT_EQ (tok0->m_kind, pp_token::kind::text);
     312            4 :   ASSERT_STREQ (((pp_token_text *)tok0)->m_value.get (),
     313              :                 "x: ");
     314              : 
     315            4 :   pp_token *tok1 = tok0->m_next;
     316            4 :   ASSERT_EQ (tok1->m_kind, pp_token::kind::begin_quote);
     317              : 
     318            4 :   pp_token *tok2 = tok1->m_next;
     319            4 :   ASSERT_EQ (tok2->m_kind, pp_token::kind::text);
     320            4 :   ASSERT_STREQ (((pp_token_text *)tok2)->m_value.get (),
     321              :                 "foo");
     322              : 
     323            4 :   pp_token *tok3 = tok2->m_next;
     324            4 :   ASSERT_EQ (tok3->m_kind, pp_token::kind::end_quote);
     325              : 
     326            4 :   pp_token *tok4 = tok3->m_next;
     327            4 :   ASSERT_EQ (tok4->m_kind, pp_token::kind::text);
     328            4 :   ASSERT_STREQ (((pp_token_text *)tok4)->m_value.get (),
     329              :                 " y: ");
     330              : 
     331            4 :   pp_token *tok5 = tok4->m_next;
     332            4 :   ASSERT_EQ (tok5->m_kind, pp_token::kind::begin_quote);
     333              : 
     334            4 :   pp_token *tok6 = tok5->m_next;
     335            4 :   ASSERT_EQ (tok6->m_kind, pp_token::kind::text);
     336            4 :   ASSERT_STREQ (((pp_token_text *)tok6)->m_value.get (),
     337              :                 "bar");
     338              : 
     339            4 :   pp_token *tok7 = tok6->m_next;
     340            4 :   ASSERT_EQ (tok7->m_kind, pp_token::kind::end_quote);
     341            4 :   ASSERT_EQ (tok7->m_next, nullptr);
     342              : 
     343              : 
     344              :   // Check that we can replay buf via pp_token_buffer_element
     345            4 :   pp_token_buffer_element e (buf);
     346            4 :   pretty_printer pp;
     347            4 :   pp_printf (&pp, "before %e after", &e);
     348            4 :   ASSERT_STREQ (pp_formatted_text (&pp), "before x: 'foo' y: 'bar' after");
     349            8 : }
     350              : 
     351              : /* Run all of the selftests within this file.  */
     352              : 
     353              : void
     354            4 : pretty_print_token_buffer_cc_tests ()
     355              : {
     356            4 :   test_empty ();
     357            4 :   test_print ();
     358            4 : }
     359              : 
     360              : } // namespace selftest
     361              : 
     362              : #endif /* 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.