LCOV - code coverage report
Current view: top level - gcc - pretty-print-format-impl.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 82.6 % 69 57
Test Date: 2026-02-28 14:20:25 Functions: 84.8 % 33 28
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Implementation detail of pp_format.
       2              :    Copyright (C) 2002-2026 Free Software Foundation, Inc.
       3              :    Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
       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              : #ifndef GCC_PRETTY_PRINT_FORMAT_IMPL_H
      22              : #define GCC_PRETTY_PRINT_FORMAT_IMPL_H
      23              : 
      24              : #include "pretty-print.h"
      25              : #include "diagnostics/event-id.h"
      26              : 
      27              : /* A struct representing a pending item to be printed within
      28              :    pp_format.
      29              : 
      30              :    These can represent:
      31              :    - a run of text within one of the output_buffers's obstacks
      32              :    - begin/end named color
      33              :    - open/close quote
      34              :    - begin/end URL
      35              :    - event IDs
      36              :    - custom data (for the formatter, for the pretty_printer,
      37              :      or the output format)
      38              : 
      39              :    These are built into pp_token_list instances.
      40              : 
      41              :    Doing so allows for interaction between:
      42              : 
      43              :    - pretty_printer formatting codes (such as C++'s %H and %I,
      44              :    which can't be printed until we've seen both)
      45              : 
      46              :    - output formats, such as text vs SARIF (so each can handle URLs
      47              :    and event IDs it its own way)
      48              : 
      49              :    - optimization records, where we want to stash data into the
      50              :    formatted messages
      51              : 
      52              :    - urlifiers: these can be run in phase 3 of formatting
      53              : 
      54              :    without needing lots of fragile logic on char pointers.
      55              : 
      56              :    To avoid needing lots of heap allocation/deallocation, pp_token
      57              :    instances are allocated in the pretty_printer's chunk_obstack:
      58              :    they must not outlive phase 3 of formatting of the given
      59              :    pp_formatted_chunks level.  */
      60              : 
      61              : struct pp_token
      62              : {
      63              : public:
      64              :   enum class kind
      65              :   {
      66              :     text,
      67              : 
      68              :     begin_color,
      69              :     end_color,
      70              : 
      71              :     begin_quote,
      72              :     end_quote,
      73              : 
      74              :     begin_url,
      75              :     end_url,
      76              : 
      77              :     event_id,
      78              : 
      79              :     custom_data,
      80              : 
      81              :     NUM_KINDS
      82              :   };
      83              : 
      84              :   pp_token (enum kind k);
      85              : 
      86              :   pp_token (const pp_token &) = delete;
      87              :   pp_token (pp_token &&) = delete;
      88              : 
      89            0 :   virtual ~pp_token () = default;
      90              : 
      91              :   pp_token &operator= (const pp_token &) = delete;
      92              :   pp_token &operator= (pp_token &&) = delete;
      93              : 
      94              :   void dump (FILE *out) const;
      95            0 :   void DEBUG_FUNCTION dump () const { dump (stderr); }
      96              : 
      97              :   static void *operator new (size_t sz, obstack &s);
      98              :   static void operator delete (void *);
      99              : 
     100              :   enum kind m_kind;
     101              : 
     102              :   // Intrusive doubly-linked list
     103              :   pp_token *m_prev;
     104              :   pp_token *m_next;
     105              : };
     106              : 
     107              : /* Subclasses of pp_token for the various kinds of token.  */
     108              : 
     109              : struct pp_token_text : public pp_token
     110              : {
     111     42812441 :   pp_token_text (label_text &&value)
     112     42812441 :   : pp_token (kind::text),
     113     42812441 :     m_value (std::move (value))
     114              :   {
     115     42812441 :     gcc_assert (m_value.get ());
     116     42812441 :   }
     117              : 
     118              :   label_text m_value;
     119              : };
     120              : 
     121              : template <>
     122              : template <>
     123              : inline bool
     124     30543235 : is_a_helper <pp_token_text *>::test (pp_token *tok)
     125              : {
     126     30543235 :   return tok->m_kind == pp_token::kind::text;
     127              : }
     128              : 
     129              : template <>
     130              : template <>
     131              : inline bool
     132         1912 : is_a_helper <const pp_token_text *>::test (const pp_token *tok)
     133              : {
     134         1912 :   return tok->m_kind == pp_token::kind::text;
     135              : }
     136              : 
     137              : struct pp_token_begin_color : public pp_token
     138              : {
     139        25831 :   pp_token_begin_color (label_text &&value)
     140        25831 :   : pp_token (kind::begin_color),
     141        25831 :     m_value (std::move (value))
     142              :   {
     143        25831 :     gcc_assert (m_value.get ());
     144        25831 :   }
     145              : 
     146              :   label_text m_value;
     147              : };
     148              : 
     149              : template <>
     150              : template <>
     151              : inline bool
     152        25829 : is_a_helper <pp_token_begin_color *>::test (pp_token *tok)
     153              : {
     154        25829 :   return tok->m_kind == pp_token::kind::begin_color;
     155              : }
     156              : 
     157              : template <>
     158              : template <>
     159              : inline bool
     160            0 : is_a_helper <const pp_token_begin_color *>::test (const pp_token *tok)
     161              : {
     162            0 :   return tok->m_kind == pp_token::kind::begin_color;
     163              : }
     164              : 
     165              : struct pp_token_end_color : public pp_token
     166              : {
     167        25831 :   pp_token_end_color ()
     168        51662 :   : pp_token (kind::end_color)
     169              :   {
     170              :   }
     171              : };
     172              : 
     173              : struct pp_token_begin_quote : public pp_token
     174              : {
     175      1106532 :   pp_token_begin_quote ()
     176      2213064 :   : pp_token (kind::begin_quote)
     177              :   {
     178              :   }
     179              : };
     180              : 
     181              : struct pp_token_end_quote : public pp_token
     182              : {
     183      1080898 :   pp_token_end_quote ()
     184      2161796 :   : pp_token (kind::end_quote)
     185              :   {
     186              :   }
     187              : };
     188              : 
     189              : struct pp_token_begin_url : public pp_token
     190              : {
     191        18894 :   pp_token_begin_url (label_text &&value)
     192        18894 :   : pp_token (kind::begin_url),
     193        18894 :     m_value (std::move (value))
     194              :   {
     195        18894 :     gcc_assert (m_value.get ());
     196        18894 :   }
     197              : 
     198              :   label_text m_value;
     199              : };
     200              : 
     201              : template <>
     202              : template <>
     203              : inline bool
     204        18894 : is_a_helper <pp_token_begin_url*>::test (pp_token *tok)
     205              : {
     206        18894 :   return tok->m_kind == pp_token::kind::begin_url;
     207              : }
     208              : 
     209              : template <>
     210              : template <>
     211              : inline bool
     212            0 : is_a_helper <const pp_token_begin_url*>::test (const pp_token *tok)
     213              : {
     214            0 :   return tok->m_kind == pp_token::kind::begin_url;
     215              : }
     216              : 
     217              : struct pp_token_end_url : public pp_token
     218              : {
     219        18894 :   pp_token_end_url ()
     220        37788 :     : pp_token (kind::end_url)
     221              :   {
     222              :   }
     223              : };
     224              : 
     225              : struct pp_token_event_id : public pp_token
     226              : {
     227        23235 :   pp_token_event_id (diagnostics::paths::event_id_t event_id)
     228        23235 :   : pp_token (kind::event_id),
     229        23235 :     m_event_id (event_id)
     230              :   {
     231        23235 :     gcc_assert (event_id.known_p ());
     232        23235 :   }
     233              : 
     234              :   diagnostics::paths::event_id_t m_event_id;
     235              : };
     236              : 
     237              : template <>
     238              : template <>
     239              : inline bool
     240        23235 : is_a_helper <pp_token_event_id *>::test (pp_token *tok)
     241              : {
     242        23235 :   return tok->m_kind == pp_token::kind::event_id;
     243              : }
     244              : 
     245              : template <>
     246              : template <>
     247              : inline bool
     248            0 : is_a_helper <const pp_token_event_id *>::test (const pp_token *tok)
     249              : {
     250            0 :   return tok->m_kind == pp_token::kind::event_id;
     251              : }
     252              : 
     253              : struct pp_token_custom_data : public pp_token
     254              : {
     255      3734471 :   class value
     256              :   {
     257              :   public:
     258           16 :     virtual ~value () {}
     259              :     virtual void dump (FILE *out) const = 0;
     260              : 
     261              :     /* Hook for lowering a custom_data token to standard tokens.
     262              :        Return true and write to OUT if possible.
     263              :        Return false for custom_data that is to be handled by
     264              :        the token_printer.  */
     265              :     virtual bool as_standard_tokens (pp_token_list &out) = 0;
     266              :   };
     267              : 
     268      3734471 :   pp_token_custom_data (std::unique_ptr<value> val)
     269      3734471 :   : pp_token (kind::custom_data),
     270      3734471 :     m_value (std::move (val))
     271              :   {
     272      3734471 :     gcc_assert (m_value.get ());
     273      3734471 :   }
     274              : 
     275              :   std::unique_ptr<value> m_value;
     276              : };
     277              : 
     278              : template <>
     279              : template <>
     280              : inline bool
     281      7468934 : is_a_helper <pp_token_custom_data *>::test (pp_token *tok)
     282              : {
     283      7468934 :   return tok->m_kind == pp_token::kind::custom_data;
     284              : }
     285              : 
     286              : template <>
     287              : template <>
     288              : inline bool
     289            0 : is_a_helper <const pp_token_custom_data *>::test (const pp_token *tok)
     290              : {
     291            0 :   return tok->m_kind == pp_token::kind::custom_data;
     292              : }
     293              : 
     294              : /* A list of pp_token, with ownership of the tokens, using
     295              :    a particular obstack to allocate its tokens.  These are
     296              :    also allocated on the obstack during formatting (or, occasionally,
     297              :    the stack).  */
     298              : 
     299              : class pp_token_list
     300              : {
     301              : public:
     302              :   // Allocate a new pp_token_list within S.
     303     49991621 :   static pp_token_list *make (obstack &s)
     304              :   {
     305     49991621 :     return new (s) pp_token_list (s);
     306              :   }
     307              :   static void *operator new (size_t sz, obstack &s);
     308              :   static void operator delete (void *);
     309              : 
     310              :   pp_token_list (obstack &s);
     311              :   pp_token_list (const pp_token_list &) = delete;
     312              :   pp_token_list (pp_token_list &&);
     313              : 
     314              :   ~pp_token_list ();
     315              : 
     316              :   pp_token &operator= (const pp_token_list &) = delete;
     317              :   pp_token &operator= (pp_token_list &&) = delete;
     318              : 
     319              : /* Make a pp_token of the given subclass, using the relevant obstack to provide
     320              :    the memory.  The pp_token must therefore not outlive the current
     321              :    pp_formatted_chunks level during formatting.  */
     322              :   template<typename Subclass, typename... Args>
     323              :   std::unique_ptr<pp_token>
     324     48847027 :   make_token (Args&&... args)
     325              :   {
     326              :     return std::unique_ptr<pp_token>
     327     48847027 :       (new (m_obstack) Subclass (std::forward<Args> (args)...));
     328              :   }
     329              : 
     330              :   template<typename Subclass, typename... Args>
     331     48809311 :   void push_back (Args&&... args)
     332              :   {
     333     48809311 :     auto tok = make_token<Subclass> (std::forward<Args> (args)...);
     334     48809311 :     push_back (std::move (tok));
     335     48809311 :   }
     336              :   void push_back_text (label_text &&text);
     337              :   void push_back_byte (char ch);
     338              :   void push_back (std::unique_ptr<pp_token> tok);
     339              :   void push_back_list (pp_token_list &&list);
     340              : 
     341              :   std::unique_ptr<pp_token> pop_front ();
     342              : 
     343              :   std::unique_ptr<pp_token> remove_token (pp_token *tok);
     344              : 
     345              :   void insert_after (std::unique_ptr<pp_token> new_tok,
     346              :                      pp_token *relative_tok);
     347              : 
     348              :   void replace_custom_tokens ();
     349              :   void merge_consecutive_text_tokens ();
     350              :   void apply_urlifier (const urlifier &urlifier);
     351              : 
     352              :   void dump (FILE *out) const;
     353            0 :   void DEBUG_FUNCTION dump () const { dump (stderr); }
     354              : 
     355              :   obstack &m_obstack;
     356              : 
     357              :   pp_token *m_first;
     358              :   pp_token *m_end;
     359              : };
     360              : 
     361              : /* The pp_formatted_chunks data structure forms a stack of the results from the
     362              :    first phase of formatting (pp_format) which have not yet been
     363              :    output (pp_output_formatted_text).  A stack is necessary because
     364              :    the diagnostic starter may decide to generate its own output by way
     365              :    of the formatter.  */
     366              : class pp_formatted_chunks
     367              : {
     368              :   friend class pretty_printer;
     369              :   friend class pp_markup::context;
     370              :   friend class output_buffer;
     371              : 
     372              : public:
     373     13411645 :   pp_token_list * const * get_token_lists () const { return m_args; }
     374              : 
     375              :   void append_formatted_chunk (obstack &s, const char *content);
     376              : 
     377              :   void dump (FILE *out, int indent) const;
     378            0 :   void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
     379              : 
     380              :   // For use in selftests
     381            8 :   pp_formatted_chunks *get_prev () const { return m_prev; }
     382              : 
     383              : private:
     384              :   /* Pointer to previous level on the stack.  */
     385              :   pp_formatted_chunks *m_prev;
     386              : 
     387              :   /* Array of chunks to output.  Each chunk is a doubly-linked list of
     388              :      pp_token.
     389              : 
     390              :      The chunks can be printed via pp_formatted_chunks::dump ().
     391              : 
     392              :      In the first phase of formatting, even-numbered chunks are
     393              :      to be output verbatim, odd-numbered chunks are format specifiers.
     394              :      For example, given:
     395              :        pp_format (pp,
     396              :                   "foo: %i, bar: %s, opt: %qs",
     397              :                   42, "baz", "-foption");
     398              : 
     399              :      after phase 1 we might have:
     400              :        (gdb) call buffer->cur_chunk_array->dump()
     401              :        0: [TEXT("foo: ")]
     402              :        1: [TEXT("i")]
     403              :        2: [TEXT(", bar: ")]
     404              :        3: [TEXT("s")]
     405              :        4: [TEXT(", opt: ")]
     406              :        5: [TEXT("qs")]
     407              : 
     408              :      The second phase replaces all odd-numbered chunks with formatted
     409              :      token lists.  In the above example, after phase 2 we might have:
     410              :        (gdb) call pp->m_buffer->cur_chunk_array->dump()
     411              :        0: [TEXT("foo: ")]
     412              :        1: [TEXT("42")]
     413              :        2: [TEXT(", bar: ")]
     414              :        3: [TEXT("baz")]
     415              :        4: [TEXT(", opt: ")]
     416              :        5: [BEGIN_QUOTE, TEXT("-foption"), END_QUOTE]
     417              :      For example the %qs has become the three tokens:
     418              :        [BEGIN_QUOTE, TEXT("-foption"), END_QUOTE]
     419              : 
     420              :      The third phase (in pp_output_formatted_text):
     421              : 
     422              :      (1) merges the tokens from all the chunks into one list,
     423              :      giving e.g.
     424              :       (gdb) call tokens.dump()
     425              :       [TEXT("foo: "), TEXT("42"), TEXT(", bar: "), TEXT("baz"),
     426              :        TEXT(", opt: "), BEGIN_QUOTE, TEXT("-foption"), END_QUOTE]
     427              : 
     428              :      (2) lowers some custom tokens into non-custom tokens
     429              : 
     430              :      (3) merges consecutive text tokens, giving e.g.:
     431              :       (gdb) call tokens.dump()
     432              :       [TEXT("foo: 42, bar: baz, option: "),
     433              :        BEGIN_QUOTE, TEXT("-foption"), END_QUOTE]
     434              : 
     435              :      (4) if provided with a urlifier, tries to apply it to quoted text,
     436              :      giving e.g:
     437              :       (gdb) call tokens.dump()
     438              :       [TEXT("foo: 42, bar: baz, option: "), BEGIN_QUOTE,
     439              :        BEGIN_URL("http://example.com"), TEXT("-foption"), END_URL, END_QUOTE]
     440              : 
     441              :      (5) emits all tokens in sequence with appropriate line-wrapping.  This
     442              :      can be overridded via the pretty_printer's token_printer, allowing for
     443              :      output formats to e.g. override how URLs are handled, or to handle
     444              :      custom_data that wasn't lowered in (2) above, e.g. for handling JSON
     445              :      output of optimization records.  */
     446              :   pp_token_list *m_args[PP_NL_ARGMAX * 2];
     447              : 
     448              :   /* The pp_tokens, pp_token_lists, and the accumulated text buffers are
     449              :      allocated within the output_buffer's chunk_obstack.  In the above
     450              :      example, the in-memory layout of the chunk_obstack might look like
     451              :      this after phase 1:
     452              : 
     453              :       + pp_formatted_chunks instance   <--- START of pp_formatted_chunks level
     454              :       |
     455              :       + pp_token_list for chunk 0 (m_first: *)
     456              :       |                                     |
     457              :       + "foo: \0"  <-------------\          |
     458              :       |                          |          |
     459              :       + pp_token_text (borrowed: *) <-------/
     460              :       |
     461              :       + pp_token_list for chunk 1
     462              :       |
     463              :       + "i\0" <------------------\
     464              :       |                          |
     465              :       + pp_token_text (borrowed: *)
     466              :       |
     467              :       +  ...etc for chunks 2 to 4...
     468              :       |
     469              :       + pp_token_list for chunk 5
     470              :       |
     471              :       + "qs\0" <-----------------\
     472              :       |                          |
     473              :       + pp_token_text (borrowed: *)
     474              :       |
     475              :       |
     476              :       V
     477              :      obstack grows this way
     478              : 
     479              :      At each stage, allocation of additional text buffers, tokens, and lists
     480              :      grow forwards in the obstack (though the internal pointers in linked
     481              :      lists might point backwards to earlier objects within the same
     482              :      pp_formatted_chunks level).  */
     483              : };
     484              : 
     485              : #endif /* GCC_PRETTY_PRINT_FORMAT_IMPL_H */
        

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.