Home | History | Annotate | Line # | Download | only in gcc
diagnostic-show-locus.cc revision 1.1
      1 /* Diagnostic subroutines for printing source-code
      2    Copyright (C) 1999-2022 Free Software Foundation, Inc.
      3    Contributed by Gabriel Dos Reis <gdr (at) codesourcery.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 "version.h"
     25 #include "demangle.h"
     26 #include "intl.h"
     27 #include "backtrace.h"
     28 #include "diagnostic.h"
     29 #include "diagnostic-color.h"
     30 #include "gcc-rich-location.h"
     31 #include "selftest.h"
     32 #include "selftest-diagnostic.h"
     33 #include "cpplib.h"
     34 
     35 #ifdef HAVE_TERMIOS_H
     36 # include <termios.h>
     37 #endif
     38 
     39 #ifdef GWINSZ_IN_SYS_IOCTL
     40 # include <sys/ioctl.h>
     41 #endif
     42 
     43 /* Disable warnings about quoting issues in the pp_xxx calls below
     44    that (intentionally) don't follow GCC diagnostic conventions.  */
     45 #if __GNUC__ >= 10
     46 #  pragma GCC diagnostic push
     47 #  pragma GCC diagnostic ignored "-Wformat-diag"
     48 #endif
     49 
     50 /* Classes for rendering source code and diagnostics, within an
     51    anonymous namespace.
     52    The work is done by "class layout", which embeds and uses
     53    "class colorizer" and "class layout_range" to get things done.  */
     54 
     55 namespace {
     56 
     57 /* The state at a given point of the source code, assuming that we're
     58    in a range: which range are we in, and whether we should draw a caret at
     59    this point.  */
     60 
     61 struct point_state
     62 {
     63   int range_idx;
     64   bool draw_caret_p;
     65 };
     66 
     67 /* A class to inject colorization codes when printing the diagnostic locus.
     68 
     69    It has one kind of colorization for each of:
     70      - normal text
     71      - range 0 (the "primary location")
     72      - range 1
     73      - range 2
     74 
     75    The class caches the lookup of the color codes for the above.
     76 
     77    The class also has responsibility for tracking which of the above is
     78    active, filtering out unnecessary changes.  This allows
     79    layout::print_source_line and layout::print_annotation_line
     80    to simply request a colorization code for *every* character they print,
     81    via this class, and have the filtering be done for them here.  */
     82 
     83 class colorizer
     84 {
     85  public:
     86   colorizer (diagnostic_context *context,
     87 	     diagnostic_t diagnostic_kind);
     88   ~colorizer ();
     89 
     90   void set_range (int range_idx)
     91   {
     92     /* Normally we emphasize the primary location, then alternate between
     93        two colors for the secondary locations.
     94        But if we're printing a run of events in a diagnostic path, that
     95        makes no sense, so print all of them with the same colorization.  */
     96     if (m_diagnostic_kind == DK_DIAGNOSTIC_PATH)
     97       set_state (0);
     98     else
     99       set_state (range_idx);
    100   }
    101   void set_normal_text () { set_state (STATE_NORMAL_TEXT); }
    102   void set_fixit_insert () { set_state (STATE_FIXIT_INSERT); }
    103   void set_fixit_delete () { set_state (STATE_FIXIT_DELETE); }
    104 
    105  private:
    106   void set_state (int state);
    107   void begin_state (int state);
    108   void finish_state (int state);
    109   const char *get_color_by_name (const char *);
    110 
    111  private:
    112   static const int STATE_NORMAL_TEXT = -1;
    113   static const int STATE_FIXIT_INSERT  = -2;
    114   static const int STATE_FIXIT_DELETE  = -3;
    115 
    116   diagnostic_context *m_context;
    117   diagnostic_t m_diagnostic_kind;
    118   int m_current_state;
    119   const char *m_range1;
    120   const char *m_range2;
    121   const char *m_fixit_insert;
    122   const char *m_fixit_delete;
    123   const char *m_stop_color;
    124 };
    125 
    126 /* In order to handle multibyte sources properly, all of this logic needs to be
    127    aware of the distinction between the number of bytes and the number of
    128    display columns occupied by a character, which are not the same for non-ASCII
    129    characters.  For example, the Unicode pi symbol, U+03C0, is encoded in UTF-8
    130    as "\xcf\x80", and thus occupies 2 bytes of space while only occupying 1
    131    display column when it is output.  A typical emoji, such as U+1F602 (in
    132    UTF-8, "\xf0\x9f\x98\x82"), requires 4 bytes and has a display width of 2.
    133 
    134    The below example line, which is also used for selftests below, shows how the
    135    display column and byte column are related:
    136 
    137      0000000001111111111222222   display
    138      1234567890123456789012345   columns
    139      SS_foo = P_bar.SS_fieldP;
    140      0000000111111111222222223   byte
    141      1356789012456789134567891   columns
    142 
    143    Here SS represents the two display columns for the U+1F602 emoji, and P
    144    represents the one display column for the U+03C0 pi symbol.  As an example, a
    145    diagnostic pointing to the final P on this line is at byte column 29 and
    146    display column 24.  This reflects the fact that the three extended characters
    147    before the final P occupy cumulatively 5 more bytes than they do display
    148    columns (a difference of 2 for each of the two SSs, and one for the other P).
    149 
    150    One or the other of the two column units is more useful depending on the
    151    context.  For instance, in order to output the caret at the correct location,
    152    we need to count display columns; in order to colorize a source line, we need
    153    to count the bytes.  All locations are provided to us as byte counts, which
    154    we augment with the display column on demand so that it can be used when
    155    needed.  This is not the most efficient way to do things since it requires
    156    looping over the whole line each time, but it should be fine for the purpose
    157    of outputting diagnostics.
    158 
    159    In order to keep straight which units (byte or display) are in use at a
    160    given time, the following enum lets us specify that explicitly.  */
    161 
    162 enum column_unit {
    163   /* Measured in raw bytes.  */
    164   CU_BYTES = 0,
    165 
    166   /* Measured in display units.  */
    167   CU_DISPLAY_COLS,
    168 
    169   /* For arrays indexed by column_unit.  */
    170   CU_NUM_UNITS
    171 };
    172 
    173 /* Utility class to augment an exploc with the corresponding display column.  */
    174 
    175 class exploc_with_display_col : public expanded_location
    176 {
    177  public:
    178   exploc_with_display_col (const expanded_location &exploc,
    179 			   const cpp_char_column_policy &policy,
    180 			   enum location_aspect aspect)
    181   : expanded_location (exploc),
    182     m_display_col (location_compute_display_column (exploc, policy))
    183   {
    184     if (exploc.column > 0)
    185       {
    186 	/* m_display_col is now the final column of the byte.
    187 	   If escaping has happened, we may want the first column instead.  */
    188 	if (aspect != LOCATION_ASPECT_FINISH)
    189 	  {
    190 	    expanded_location prev_exploc (exploc);
    191 	    prev_exploc.column--;
    192 	    int prev_display_col
    193 	      = (location_compute_display_column (prev_exploc, policy));
    194 	    m_display_col = prev_display_col + 1;
    195 	  }
    196       }
    197   }
    198 
    199   int m_display_col;
    200 };
    201 
    202 
    203 /* A point within a layout_range; similar to an exploc_with_display_col,
    204    but after filtering on file.  */
    205 
    206 class layout_point
    207 {
    208  public:
    209   layout_point (const exploc_with_display_col &exploc)
    210     : m_line (exploc.line)
    211   {
    212     m_columns[CU_BYTES] = exploc.column;
    213     m_columns[CU_DISPLAY_COLS] = exploc.m_display_col;
    214   }
    215 
    216   linenum_type m_line;
    217   int m_columns[CU_NUM_UNITS];
    218 };
    219 
    220 /* A class for use by "class layout" below: a filtered location_range.  */
    221 
    222 class layout_range
    223 {
    224  public:
    225   layout_range (const exploc_with_display_col &start_exploc,
    226 		const exploc_with_display_col &finish_exploc,
    227 		enum range_display_kind range_display_kind,
    228 		const exploc_with_display_col &caret_exploc,
    229 		unsigned original_idx,
    230 		const range_label *label);
    231 
    232   bool contains_point (linenum_type row, int column,
    233 		       enum column_unit col_unit) const;
    234   bool intersects_line_p (linenum_type row) const;
    235 
    236   layout_point m_start;
    237   layout_point m_finish;
    238   enum range_display_kind m_range_display_kind;
    239   layout_point m_caret;
    240   unsigned m_original_idx;
    241   const range_label *m_label;
    242 };
    243 
    244 /* A struct for use by layout::print_source_line for telling
    245    layout::print_annotation_line the extents of the source line that
    246    it printed, so that underlines can be clipped appropriately.  Units
    247    are 1-based display columns.  */
    248 
    249 struct line_bounds
    250 {
    251   int m_first_non_ws_disp_col;
    252   int m_last_non_ws_disp_col;
    253 
    254   line_bounds ()
    255   {
    256     m_first_non_ws_disp_col = INT_MAX;
    257     m_last_non_ws_disp_col = 0;
    258   }
    259 };
    260 
    261 /* A range of contiguous source lines within a layout (e.g. "lines 5-10"
    262    or "line 23").  During the layout ctor, layout::calculate_line_spans
    263    splits the pertinent source lines into a list of disjoint line_span
    264    instances (e.g. lines 5-10, lines 15-20, line 23).  */
    265 
    266 class line_span
    267 {
    268 public:
    269   line_span (linenum_type first_line, linenum_type last_line)
    270     : m_first_line (first_line), m_last_line (last_line)
    271   {
    272     gcc_assert (first_line <= last_line);
    273   }
    274   linenum_type get_first_line () const { return m_first_line; }
    275   linenum_type get_last_line () const { return m_last_line; }
    276 
    277   bool contains_line_p (linenum_type line) const
    278   {
    279     return line >= m_first_line && line <= m_last_line;
    280   }
    281 
    282   static int comparator (const void *p1, const void *p2)
    283   {
    284     const line_span *ls1 = (const line_span *)p1;
    285     const line_span *ls2 = (const line_span *)p2;
    286     int first_line_cmp = compare (ls1->m_first_line, ls2->m_first_line);
    287     if (first_line_cmp)
    288       return first_line_cmp;
    289     return compare (ls1->m_last_line, ls2->m_last_line);
    290   }
    291 
    292   linenum_type m_first_line;
    293   linenum_type m_last_line;
    294 };
    295 
    296 #if CHECKING_P
    297 
    298 /* Selftests for line_span.  */
    299 
    300 static void
    301 test_line_span ()
    302 {
    303   line_span line_one (1, 1);
    304   ASSERT_EQ (1, line_one.get_first_line ());
    305   ASSERT_EQ (1, line_one.get_last_line ());
    306   ASSERT_FALSE (line_one.contains_line_p (0));
    307   ASSERT_TRUE (line_one.contains_line_p (1));
    308   ASSERT_FALSE (line_one.contains_line_p (2));
    309 
    310   line_span lines_1_to_3 (1, 3);
    311   ASSERT_EQ (1, lines_1_to_3.get_first_line ());
    312   ASSERT_EQ (3, lines_1_to_3.get_last_line ());
    313   ASSERT_TRUE (lines_1_to_3.contains_line_p (1));
    314   ASSERT_TRUE (lines_1_to_3.contains_line_p (3));
    315 
    316   ASSERT_EQ (0, line_span::comparator (&line_one, &line_one));
    317   ASSERT_GT (line_span::comparator (&lines_1_to_3, &line_one), 0);
    318   ASSERT_LT (line_span::comparator (&line_one, &lines_1_to_3), 0);
    319 
    320   /* A linenum > 2^31.  */
    321   const linenum_type LARGEST_LINE = 0xffffffff;
    322   line_span largest_line (LARGEST_LINE, LARGEST_LINE);
    323   ASSERT_EQ (LARGEST_LINE, largest_line.get_first_line ());
    324   ASSERT_EQ (LARGEST_LINE, largest_line.get_last_line ());
    325 
    326   ASSERT_GT (line_span::comparator (&largest_line, &line_one), 0);
    327   ASSERT_LT (line_span::comparator (&line_one, &largest_line), 0);
    328 }
    329 
    330 #endif /* #if CHECKING_P */
    331 
    332 /* A bundle of information containing how to print unicode
    333    characters and bytes when quoting source code.
    334 
    335    Provides a unified place to support escaping some subset
    336    of characters to some format.
    337 
    338    Extends char_column_policy; printing is split out to avoid
    339    libcpp having to know about pretty_printer.  */
    340 
    341 struct char_display_policy : public cpp_char_column_policy
    342 {
    343  public:
    344   char_display_policy (int tabstop,
    345 		       int (*width_cb) (cppchar_t c),
    346 		       void (*print_cb) (pretty_printer *pp,
    347 					 const cpp_decoded_char &cp))
    348   : cpp_char_column_policy (tabstop, width_cb),
    349     m_print_cb (print_cb)
    350   {
    351   }
    352 
    353   void (*m_print_cb) (pretty_printer *pp,
    354 		      const cpp_decoded_char &cp);
    355 };
    356 
    357 /* A class to control the overall layout when printing a diagnostic.
    358 
    359    The layout is determined within the constructor.
    360    It is then printed by repeatedly calling the "print_source_line",
    361    "print_annotation_line" and "print_any_fixits" methods.
    362 
    363    We assume we have disjoint ranges.  */
    364 
    365 class layout
    366 {
    367  public:
    368   layout (diagnostic_context *context,
    369 	  rich_location *richloc,
    370 	  diagnostic_t diagnostic_kind);
    371 
    372   bool maybe_add_location_range (const location_range *loc_range,
    373 				 unsigned original_idx,
    374 				 bool restrict_to_current_line_spans);
    375 
    376   int get_num_line_spans () const { return m_line_spans.length (); }
    377   const line_span *get_line_span (int idx) const { return &m_line_spans[idx]; }
    378 
    379   int get_linenum_width () const { return m_linenum_width; }
    380   int get_x_offset_display () const { return m_x_offset_display; }
    381 
    382   void print_gap_in_line_numbering ();
    383   bool print_heading_for_line_span_index_p (int line_span_idx) const;
    384 
    385   expanded_location get_expanded_location (const line_span *) const;
    386 
    387   void print_line (linenum_type row);
    388 
    389   void on_bad_codepoint (const char *ptr, cppchar_t ch, size_t ch_sz);
    390 
    391  private:
    392   bool will_show_line_p (linenum_type row) const;
    393   void print_leading_fixits (linenum_type row);
    394   line_bounds print_source_line (linenum_type row, const char *line,
    395 				 int line_bytes);
    396   bool should_print_annotation_line_p (linenum_type row) const;
    397   void start_annotation_line (char margin_char = ' ') const;
    398   void print_annotation_line (linenum_type row, const line_bounds lbounds);
    399   void print_any_labels (linenum_type row);
    400   void print_trailing_fixits (linenum_type row);
    401 
    402   bool annotation_line_showed_range_p (linenum_type line, int start_column,
    403 				       int finish_column) const;
    404   void show_ruler (int max_column) const;
    405 
    406   bool validate_fixit_hint_p (const fixit_hint *hint);
    407 
    408   void calculate_line_spans ();
    409   void calculate_linenum_width ();
    410   void calculate_x_offset_display ();
    411 
    412   void print_newline ();
    413 
    414   bool
    415   get_state_at_point (/* Inputs.  */
    416 		      linenum_type row, int column,
    417 		      int first_non_ws, int last_non_ws,
    418 		      enum column_unit col_unit,
    419 		      /* Outputs.  */
    420 		      point_state *out_state);
    421 
    422   int
    423   get_x_bound_for_row (linenum_type row, int caret_column,
    424 		       int last_non_ws);
    425 
    426   void
    427   move_to_column (int *column, int dest_column, bool add_left_margin);
    428 
    429  private:
    430   diagnostic_context *m_context;
    431   pretty_printer *m_pp;
    432   char_display_policy m_policy;
    433   location_t m_primary_loc;
    434   exploc_with_display_col m_exploc;
    435   colorizer m_colorizer;
    436   bool m_colorize_source_p;
    437   bool m_show_labels_p;
    438   bool m_show_line_numbers_p;
    439   bool m_diagnostic_path_p;
    440   auto_vec <layout_range> m_layout_ranges;
    441   auto_vec <const fixit_hint *> m_fixit_hints;
    442   auto_vec <line_span> m_line_spans;
    443   int m_linenum_width;
    444   int m_x_offset_display;
    445   bool m_escape_on_output;
    446 };
    447 
    448 /* Implementation of "class colorizer".  */
    449 
    450 /* The constructor for "colorizer".  Lookup and store color codes for the
    451    different kinds of things we might need to print.  */
    452 
    453 colorizer::colorizer (diagnostic_context *context,
    454 		      diagnostic_t diagnostic_kind) :
    455   m_context (context),
    456   m_diagnostic_kind (diagnostic_kind),
    457   m_current_state (STATE_NORMAL_TEXT)
    458 {
    459   m_range1 = get_color_by_name ("range1");
    460   m_range2 = get_color_by_name ("range2");
    461   m_fixit_insert = get_color_by_name ("fixit-insert");
    462   m_fixit_delete = get_color_by_name ("fixit-delete");
    463   m_stop_color = colorize_stop (pp_show_color (context->printer));
    464 }
    465 
    466 /* The destructor for "colorize".  If colorization is on, print a code to
    467    turn it off.  */
    468 
    469 colorizer::~colorizer ()
    470 {
    471   finish_state (m_current_state);
    472 }
    473 
    474 /* Update state, printing color codes if necessary if there's a state
    475    change.  */
    476 
    477 void
    478 colorizer::set_state (int new_state)
    479 {
    480   if (m_current_state != new_state)
    481     {
    482       finish_state (m_current_state);
    483       m_current_state = new_state;
    484       begin_state (new_state);
    485     }
    486 }
    487 
    488 /* Turn on any colorization for STATE.  */
    489 
    490 void
    491 colorizer::begin_state (int state)
    492 {
    493   switch (state)
    494     {
    495     case STATE_NORMAL_TEXT:
    496       break;
    497 
    498     case STATE_FIXIT_INSERT:
    499       pp_string (m_context->printer, m_fixit_insert);
    500       break;
    501 
    502     case STATE_FIXIT_DELETE:
    503       pp_string (m_context->printer, m_fixit_delete);
    504       break;
    505 
    506     case 0:
    507       /* Make range 0 be the same color as the "kind" text
    508 	 (error vs warning vs note).  */
    509       pp_string
    510 	(m_context->printer,
    511 	 colorize_start (pp_show_color (m_context->printer),
    512 			 diagnostic_get_color_for_kind (m_diagnostic_kind)));
    513       break;
    514 
    515     case 1:
    516       pp_string (m_context->printer, m_range1);
    517       break;
    518 
    519     case 2:
    520       pp_string (m_context->printer, m_range2);
    521       break;
    522 
    523     default:
    524       /* For ranges beyond 2, alternate between color 1 and color 2.  */
    525       {
    526 	gcc_assert (state > 2);
    527 	pp_string (m_context->printer,
    528 		   state % 2 ? m_range1 : m_range2);
    529       }
    530       break;
    531     }
    532 }
    533 
    534 /* Turn off any colorization for STATE.  */
    535 
    536 void
    537 colorizer::finish_state (int state)
    538 {
    539   if (state != STATE_NORMAL_TEXT)
    540     pp_string (m_context->printer, m_stop_color);
    541 }
    542 
    543 /* Get the color code for NAME (or the empty string if
    544    colorization is disabled).  */
    545 
    546 const char *
    547 colorizer::get_color_by_name (const char *name)
    548 {
    549   return colorize_start (pp_show_color (m_context->printer), name);
    550 }
    551 
    552 /* Implementation of class layout_range.  */
    553 
    554 /* The constructor for class layout_range.
    555    Initialize various layout_point fields from expanded_location
    556    equivalents; we've already filtered on file.  */
    557 
    558 layout_range::layout_range (const exploc_with_display_col &start_exploc,
    559 			    const exploc_with_display_col &finish_exploc,
    560 			    enum range_display_kind range_display_kind,
    561 			    const exploc_with_display_col &caret_exploc,
    562 			    unsigned original_idx,
    563 			    const range_label *label)
    564 : m_start (start_exploc),
    565   m_finish (finish_exploc),
    566   m_range_display_kind (range_display_kind),
    567   m_caret (caret_exploc),
    568   m_original_idx (original_idx),
    569   m_label (label)
    570 {
    571 }
    572 
    573 /* Is (column, row) within the given range?
    574    We've already filtered on the file.
    575 
    576    Ranges are closed (both limits are within the range).
    577 
    578    Example A: a single-line range:
    579      start:  (col=22, line=2)
    580      finish: (col=38, line=2)
    581 
    582   |00000011111111112222222222333333333344444444444
    583   |34567890123456789012345678901234567890123456789
    584 --+-----------------------------------------------
    585 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    586 02|bbbbbbbbbbbbbbbbbbbSwwwwwwwwwwwwwwwFaaaaaaaaaaa
    587 03|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    588 
    589    Example B: a multiline range with
    590      start:  (col=14, line=3)
    591      finish: (col=08, line=5)
    592 
    593   |00000011111111112222222222333333333344444444444
    594   |34567890123456789012345678901234567890123456789
    595 --+-----------------------------------------------
    596 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    597 02|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    598 03|bbbbbbbbbbbSwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
    599 04|wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
    600 05|wwwwwFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    601 06|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    602 --+-----------------------------------------------
    603 
    604    Legend:
    605    - 'b' indicates a point *before* the range
    606    - 'S' indicates the start of the range
    607    - 'w' indicates a point within the range
    608    - 'F' indicates the finish of the range (which is
    609 	 within it).
    610    - 'a' indicates a subsequent point *after* the range.
    611 
    612    COL_UNIT controls whether we check the byte column or
    613    the display column; one or the other is more convenient
    614    depending on the context.  */
    615 
    616 bool
    617 layout_range::contains_point (linenum_type row, int column,
    618 			      enum column_unit col_unit) const
    619 {
    620   gcc_assert (m_start.m_line <= m_finish.m_line);
    621   /* ...but the equivalent isn't true for the columns;
    622      consider example B in the comment above.  */
    623 
    624   if (row < m_start.m_line)
    625     /* Points before the first line of the range are
    626        outside it (corresponding to line 01 in example A
    627        and lines 01 and 02 in example B above).  */
    628     return false;
    629 
    630   if (row == m_start.m_line)
    631     /* On same line as start of range (corresponding
    632        to line 02 in example A and line 03 in example B).  */
    633     {
    634       if (column < m_start.m_columns[col_unit])
    635 	/* Points on the starting line of the range, but
    636 	   before the column in which it begins.  */
    637 	return false;
    638 
    639       if (row < m_finish.m_line)
    640 	/* This is a multiline range; the point
    641 	   is within it (corresponds to line 03 in example B
    642 	   from column 14 onwards) */
    643 	return true;
    644       else
    645 	{
    646 	  /* This is a single-line range.  */
    647 	  gcc_assert (row == m_finish.m_line);
    648 	  return column <= m_finish.m_columns[col_unit];
    649 	}
    650     }
    651 
    652   /* The point is in a line beyond that containing the
    653      start of the range: lines 03 onwards in example A,
    654      and lines 04 onwards in example B.  */
    655   gcc_assert (row > m_start.m_line);
    656 
    657   if (row > m_finish.m_line)
    658     /* The point is beyond the final line of the range
    659        (lines 03 onwards in example A, and lines 06 onwards
    660        in example B).  */
    661     return false;
    662 
    663   if (row < m_finish.m_line)
    664     {
    665       /* The point is in a line that's fully within a multiline
    666 	 range (e.g. line 04 in example B).  */
    667       gcc_assert (m_start.m_line < m_finish.m_line);
    668       return true;
    669     }
    670 
    671   gcc_assert (row ==  m_finish.m_line);
    672 
    673   return column <= m_finish.m_columns[col_unit];
    674 }
    675 
    676 /* Does this layout_range contain any part of line ROW?  */
    677 
    678 bool
    679 layout_range::intersects_line_p (linenum_type row) const
    680 {
    681   gcc_assert (m_start.m_line <= m_finish.m_line);
    682   if (row < m_start.m_line)
    683     return false;
    684   if (row > m_finish.m_line)
    685     return false;
    686   return true;
    687 }
    688 
    689 #if CHECKING_P
    690 
    691 /* Default for when we don't care what the tab expansion is set to.  */
    692 static const int def_tabstop = 8;
    693 
    694 static cpp_char_column_policy def_policy ()
    695 {
    696   return cpp_char_column_policy (def_tabstop, cpp_wcwidth);
    697 }
    698 
    699 /* Create some expanded locations for testing layout_range.  The filename
    700    member of the explocs is set to the empty string.  This member will only be
    701    inspected by the calls to location_compute_display_column() made from the
    702    layout_point constructors.  That function will check for an empty filename
    703    argument and not attempt to open it, rather treating the non-existent data
    704    as if the display width were the same as the byte count.  Tests exercising a
    705    real difference between byte count and display width are performed later,
    706    e.g. in test_diagnostic_show_locus_one_liner_utf8().  */
    707 
    708 static layout_range
    709 make_range (int start_line, int start_col, int end_line, int end_col)
    710 {
    711   const expanded_location start_exploc
    712     = {"", start_line, start_col, NULL, false};
    713   const expanded_location finish_exploc
    714     = {"", end_line, end_col, NULL, false};
    715   return layout_range (exploc_with_display_col (start_exploc, def_policy (),
    716 						LOCATION_ASPECT_START),
    717 		       exploc_with_display_col (finish_exploc, def_policy (),
    718 						LOCATION_ASPECT_FINISH),
    719 		       SHOW_RANGE_WITHOUT_CARET,
    720 		       exploc_with_display_col (start_exploc, def_policy (),
    721 						LOCATION_ASPECT_CARET),
    722 		       0, NULL);
    723 }
    724 
    725 /* Selftests for layout_range::contains_point and
    726    layout_range::intersects_line_p.  */
    727 
    728 /* Selftest for layout_range, where the layout_range
    729    is a range with start==end i.e. a single point.  */
    730 
    731 static void
    732 test_layout_range_for_single_point ()
    733 {
    734   layout_range point = make_range (7, 10, 7, 10);
    735 
    736   /* Tests for layout_range::contains_point.  */
    737 
    738   for (int i = 0; i != CU_NUM_UNITS; ++i)
    739     {
    740       const enum column_unit col_unit = (enum column_unit) i;
    741 
    742       /* Before the line.  */
    743       ASSERT_FALSE (point.contains_point (6, 1, col_unit));
    744 
    745       /* On the line, but before start.  */
    746       ASSERT_FALSE (point.contains_point (7, 9, col_unit));
    747 
    748       /* At the point.  */
    749       ASSERT_TRUE (point.contains_point (7, 10, col_unit));
    750 
    751       /* On the line, after the point.  */
    752       ASSERT_FALSE (point.contains_point (7, 11, col_unit));
    753 
    754       /* After the line.  */
    755       ASSERT_FALSE (point.contains_point (8, 1, col_unit));
    756     }
    757 
    758   /* Tests for layout_range::intersects_line_p.  */
    759   ASSERT_FALSE (point.intersects_line_p (6));
    760   ASSERT_TRUE (point.intersects_line_p (7));
    761   ASSERT_FALSE (point.intersects_line_p (8));
    762 }
    763 
    764 /* Selftest for layout_range, where the layout_range
    765    is the single-line range shown as "Example A" above.  */
    766 
    767 static void
    768 test_layout_range_for_single_line ()
    769 {
    770   layout_range example_a = make_range (2, 22, 2, 38);
    771 
    772   /* Tests for layout_range::contains_point.  */
    773 
    774   for (int i = 0; i != CU_NUM_UNITS; ++i)
    775     {
    776       const enum column_unit col_unit = (enum column_unit) i;
    777 
    778       /* Before the line.  */
    779       ASSERT_FALSE (example_a.contains_point (1, 1, col_unit));
    780 
    781       /* On the line, but before start.  */
    782       ASSERT_FALSE (example_a.contains_point (2, 21, col_unit));
    783 
    784       /* On the line, at the start.  */
    785       ASSERT_TRUE (example_a.contains_point (2, 22, col_unit));
    786 
    787       /* On the line, within the range.  */
    788       ASSERT_TRUE (example_a.contains_point (2, 23, col_unit));
    789 
    790       /* On the line, at the end.  */
    791       ASSERT_TRUE (example_a.contains_point (2, 38, col_unit));
    792 
    793       /* On the line, after the end.  */
    794       ASSERT_FALSE (example_a.contains_point (2, 39, col_unit));
    795 
    796       /* After the line.  */
    797       ASSERT_FALSE (example_a.contains_point (2, 39, col_unit));
    798     }
    799 
    800   /* Tests for layout_range::intersects_line_p.  */
    801   ASSERT_FALSE (example_a.intersects_line_p (1));
    802   ASSERT_TRUE (example_a.intersects_line_p (2));
    803   ASSERT_FALSE (example_a.intersects_line_p (3));
    804 }
    805 
    806 /* Selftest for layout_range, where the layout_range
    807    is the multi-line range shown as "Example B" above.  */
    808 
    809 static void
    810 test_layout_range_for_multiple_lines ()
    811 {
    812   layout_range example_b = make_range (3, 14, 5, 8);
    813 
    814   /* Tests for layout_range::contains_point.  */
    815 
    816   for (int i = 0; i != CU_NUM_UNITS; ++i)
    817     {
    818       const enum column_unit col_unit = (enum column_unit) i;
    819 
    820       /* Before first line.  */
    821       ASSERT_FALSE (example_b.contains_point (1, 1, col_unit));
    822 
    823       /* On the first line, but before start.  */
    824       ASSERT_FALSE (example_b.contains_point (3, 13, col_unit));
    825 
    826       /* At the start.  */
    827       ASSERT_TRUE (example_b.contains_point (3, 14, col_unit));
    828 
    829       /* On the first line, within the range.  */
    830       ASSERT_TRUE (example_b.contains_point (3, 15, col_unit));
    831 
    832       /* On an interior line.
    833 	 The column number should not matter; try various boundary
    834 	 values.  */
    835       ASSERT_TRUE (example_b.contains_point (4, 1, col_unit));
    836       ASSERT_TRUE (example_b.contains_point (4, 7, col_unit));
    837       ASSERT_TRUE (example_b.contains_point (4, 8, col_unit));
    838       ASSERT_TRUE (example_b.contains_point (4, 9, col_unit));
    839       ASSERT_TRUE (example_b.contains_point (4, 13, col_unit));
    840       ASSERT_TRUE (example_b.contains_point (4, 14, col_unit));
    841       ASSERT_TRUE (example_b.contains_point (4, 15, col_unit));
    842 
    843       /* On the final line, before the end.  */
    844       ASSERT_TRUE (example_b.contains_point (5, 7, col_unit));
    845 
    846       /* On the final line, at the end.  */
    847       ASSERT_TRUE (example_b.contains_point (5, 8, col_unit));
    848 
    849       /* On the final line, after the end.  */
    850       ASSERT_FALSE (example_b.contains_point (5, 9, col_unit));
    851 
    852       /* After the line.  */
    853       ASSERT_FALSE (example_b.contains_point (6, 1, col_unit));
    854     }
    855 
    856   /* Tests for layout_range::intersects_line_p.  */
    857   ASSERT_FALSE (example_b.intersects_line_p (2));
    858   ASSERT_TRUE (example_b.intersects_line_p (3));
    859   ASSERT_TRUE (example_b.intersects_line_p (4));
    860   ASSERT_TRUE (example_b.intersects_line_p (5));
    861   ASSERT_FALSE (example_b.intersects_line_p (6));
    862 }
    863 
    864 #endif /* #if CHECKING_P */
    865 
    866 /* Given a source line LINE of length LINE_BYTES bytes, determine the length
    867    (still in bytes, not display cols) without any trailing whitespace.  */
    868 
    869 static int
    870 get_line_bytes_without_trailing_whitespace (const char *line, int line_bytes)
    871 {
    872   int result = line_bytes;
    873   while (result > 0)
    874     {
    875       char ch = line[result - 1];
    876       if (ch == ' ' || ch == '\t' || ch == '\r')
    877 	result--;
    878       else
    879 	break;
    880     }
    881   gcc_assert (result >= 0);
    882   gcc_assert (result <= line_bytes);
    883   gcc_assert (result == 0 ||
    884 	      (line[result - 1] != ' '
    885 	       && line[result -1] != '\t'
    886 	       && line[result -1] != '\r'));
    887   return result;
    888 }
    889 
    890 #if CHECKING_P
    891 
    892 /* A helper function for testing get_line_bytes_without_trailing_whitespace.  */
    893 
    894 static void
    895 assert_eq (const char *line, int expected_bytes)
    896 {
    897   int actual_value
    898     = get_line_bytes_without_trailing_whitespace (line, strlen (line));
    899   ASSERT_EQ (actual_value, expected_bytes);
    900 }
    901 
    902 /* Verify that get_line_bytes_without_trailing_whitespace is sane for
    903    various inputs.  It is not required to handle newlines.  */
    904 
    905 static void
    906 test_get_line_bytes_without_trailing_whitespace ()
    907 {
    908   assert_eq ("", 0);
    909   assert_eq (" ", 0);
    910   assert_eq ("\t", 0);
    911   assert_eq ("\r", 0);
    912   assert_eq ("hello world", 11);
    913   assert_eq ("hello world     ", 11);
    914   assert_eq ("hello world     \t\t  ", 11);
    915   assert_eq ("hello world\r", 11);
    916 }
    917 
    918 #endif /* #if CHECKING_P */
    919 
    920 /* Helper function for layout's ctor, for sanitizing locations relative
    921    to the primary location within a diagnostic.
    922 
    923    Compare LOC_A and LOC_B to see if it makes sense to print underlines
    924    connecting their expanded locations.  Doing so is only guaranteed to
    925    make sense if the locations share the same macro expansion "history"
    926    i.e. they can be traced through the same macro expansions, eventually
    927    reaching an ordinary map.
    928 
    929    This may be too strong a condition, but it effectively sanitizes
    930    PR c++/70105, which has an example of printing an expression where the
    931    final location of the expression is in a different macro, which
    932    erroneously was leading to hundreds of lines of irrelevant source
    933    being printed.  */
    934 
    935 static bool
    936 compatible_locations_p (location_t loc_a, location_t loc_b)
    937 {
    938   if (IS_ADHOC_LOC (loc_a))
    939     loc_a = get_location_from_adhoc_loc (line_table, loc_a);
    940   if (IS_ADHOC_LOC (loc_b))
    941     loc_b = get_location_from_adhoc_loc (line_table, loc_b);
    942 
    943   /* If either location is one of the special locations outside of a
    944      linemap, they are only compatible if they are equal.  */
    945   if (loc_a < RESERVED_LOCATION_COUNT
    946       || loc_b < RESERVED_LOCATION_COUNT)
    947     return loc_a == loc_b;
    948 
    949   const line_map *map_a = linemap_lookup (line_table, loc_a);
    950   linemap_assert (map_a);
    951 
    952   const line_map *map_b = linemap_lookup (line_table, loc_b);
    953   linemap_assert (map_b);
    954 
    955   /* Are they within the same map?  */
    956   if (map_a == map_b)
    957     {
    958       /* Are both within the same macro expansion?  */
    959       if (linemap_macro_expansion_map_p (map_a))
    960 	{
    961 	  /* If so, then they're only compatible if either both are
    962 	     from the macro definition, or both from the macro arguments.  */
    963 	  bool loc_a_from_defn
    964 	    = linemap_location_from_macro_definition_p (line_table, loc_a);
    965 	  bool loc_b_from_defn
    966 	    = linemap_location_from_macro_definition_p (line_table, loc_b);
    967 	  if (loc_a_from_defn != loc_b_from_defn)
    968 	    return false;
    969 
    970 	  /* Expand each location towards the spelling location, and
    971 	     recurse.  */
    972 	  const line_map_macro *macro_map = linemap_check_macro (map_a);
    973 	  location_t loc_a_toward_spelling
    974 	    = linemap_macro_map_loc_unwind_toward_spelling (line_table,
    975 							    macro_map,
    976 							    loc_a);
    977 	  location_t loc_b_toward_spelling
    978 	    = linemap_macro_map_loc_unwind_toward_spelling (line_table,
    979 							    macro_map,
    980 							    loc_b);
    981 	  return compatible_locations_p (loc_a_toward_spelling,
    982 					 loc_b_toward_spelling);
    983 	}
    984 
    985       /* Otherwise they are within the same ordinary map.  */
    986       return true;
    987     }
    988   else
    989     {
    990       /* Within different maps.  */
    991 
    992       /* If either is within a macro expansion, they are incompatible.  */
    993       if (linemap_macro_expansion_map_p (map_a)
    994 	  || linemap_macro_expansion_map_p (map_b))
    995 	return false;
    996 
    997       /* Within two different ordinary maps; they are compatible iff they
    998 	 are in the same file.  */
    999       const line_map_ordinary *ord_map_a = linemap_check_ordinary (map_a);
   1000       const line_map_ordinary *ord_map_b = linemap_check_ordinary (map_b);
   1001       return ord_map_a->to_file == ord_map_b->to_file;
   1002     }
   1003 }
   1004 
   1005 /* Comparator for sorting fix-it hints.  */
   1006 
   1007 static int
   1008 fixit_cmp (const void *p_a, const void *p_b)
   1009 {
   1010   const fixit_hint * hint_a = *static_cast<const fixit_hint * const *> (p_a);
   1011   const fixit_hint * hint_b = *static_cast<const fixit_hint * const *> (p_b);
   1012   return hint_a->get_start_loc () - hint_b->get_start_loc ();
   1013 }
   1014 
   1015 /* Callbacks for use when not escaping the source.  */
   1016 
   1017 /* The default callback for char_column_policy::m_width_cb is cpp_wcwidth.  */
   1018 
   1019 /* Callback for char_display_policy::m_print_cb for printing source chars
   1020    when not escaping the source.  */
   1021 
   1022 static void
   1023 default_print_decoded_ch (pretty_printer *pp,
   1024 			  const cpp_decoded_char &decoded_ch)
   1025 {
   1026   for (const char *ptr = decoded_ch.m_start_byte;
   1027        ptr != decoded_ch.m_next_byte; ptr++)
   1028     {
   1029       if (*ptr == '\0' || *ptr == '\r')
   1030 	{
   1031 	  pp_space (pp);
   1032 	  continue;
   1033 	}
   1034 
   1035       pp_character (pp, *ptr);
   1036     }
   1037 }
   1038 
   1039 /* Callbacks for use with DIAGNOSTICS_ESCAPE_FORMAT_BYTES.  */
   1040 
   1041 static const int width_per_escaped_byte = 4;
   1042 
   1043 /* Callback for char_column_policy::m_width_cb for determining the
   1044    display width when escaping with DIAGNOSTICS_ESCAPE_FORMAT_BYTES.  */
   1045 
   1046 static int
   1047 escape_as_bytes_width (cppchar_t ch)
   1048 {
   1049   if (ch < 0x80 && ISPRINT (ch))
   1050     return cpp_wcwidth (ch);
   1051   else
   1052     {
   1053       if (ch <=   0x7F) return 1 * width_per_escaped_byte;
   1054       if (ch <=  0x7FF) return 2 * width_per_escaped_byte;
   1055       if (ch <= 0xFFFF) return 3 * width_per_escaped_byte;
   1056       return 4 * width_per_escaped_byte;
   1057     }
   1058 }
   1059 
   1060 /* Callback for char_display_policy::m_print_cb for printing source chars
   1061    when escaping with DIAGNOSTICS_ESCAPE_FORMAT_BYTES.  */
   1062 
   1063 static void
   1064 escape_as_bytes_print (pretty_printer *pp,
   1065 		       const cpp_decoded_char &decoded_ch)
   1066 {
   1067   if (!decoded_ch.m_valid_ch)
   1068     {
   1069       for (const char *iter = decoded_ch.m_start_byte;
   1070 	   iter != decoded_ch.m_next_byte; ++iter)
   1071 	{
   1072 	  char buf[16];
   1073 	  sprintf (buf, "<%02x>", (unsigned char)*iter);
   1074 	  pp_string (pp, buf);
   1075 	}
   1076       return;
   1077     }
   1078 
   1079   cppchar_t ch = decoded_ch.m_ch;
   1080   if (ch < 0x80 && ISPRINT (ch))
   1081     pp_character (pp, ch);
   1082   else
   1083     {
   1084       for (const char *iter = decoded_ch.m_start_byte;
   1085 	   iter < decoded_ch.m_next_byte; ++iter)
   1086 	{
   1087 	  char buf[16];
   1088 	  sprintf (buf, "<%02x>", (unsigned char)*iter);
   1089 	  pp_string (pp, buf);
   1090 	}
   1091     }
   1092 }
   1093 
   1094 /* Callbacks for use with DIAGNOSTICS_ESCAPE_FORMAT_UNICODE.  */
   1095 
   1096 /* Callback for char_column_policy::m_width_cb for determining the
   1097    display width when escaping with DIAGNOSTICS_ESCAPE_FORMAT_UNICODE.  */
   1098 
   1099 static int
   1100 escape_as_unicode_width (cppchar_t ch)
   1101 {
   1102   if (ch < 0x80 && ISPRINT (ch))
   1103     return cpp_wcwidth (ch);
   1104   else
   1105     {
   1106       // Width of "<U+%04x>"
   1107       if (ch > 0xfffff)
   1108 	return 10;
   1109       else if (ch > 0xffff)
   1110 	return 9;
   1111       else
   1112 	return 8;
   1113     }
   1114 }
   1115 
   1116 /* Callback for char_display_policy::m_print_cb for printing source chars
   1117    when escaping with DIAGNOSTICS_ESCAPE_FORMAT_UNICODE.  */
   1118 
   1119 static void
   1120 escape_as_unicode_print (pretty_printer *pp,
   1121 			 const cpp_decoded_char &decoded_ch)
   1122 {
   1123   if (!decoded_ch.m_valid_ch)
   1124     {
   1125       escape_as_bytes_print (pp, decoded_ch);
   1126       return;
   1127     }
   1128 
   1129   cppchar_t ch = decoded_ch.m_ch;
   1130   if (ch < 0x80 && ISPRINT (ch))
   1131     pp_character (pp, ch);
   1132   else
   1133     {
   1134       char buf[16];
   1135       sprintf (buf, "<U+%04X>", ch);
   1136       pp_string (pp, buf);
   1137     }
   1138 }
   1139 
   1140 /* Populate a char_display_policy based on DC and RICHLOC.  */
   1141 
   1142 static char_display_policy
   1143 make_policy (const diagnostic_context &dc,
   1144 	     const rich_location &richloc)
   1145 {
   1146   /* The default is to not escape non-ASCII bytes.  */
   1147   char_display_policy result
   1148     (dc.tabstop, cpp_wcwidth, default_print_decoded_ch);
   1149 
   1150   /* If the diagnostic suggests escaping non-ASCII bytes, then
   1151      use policy from user-supplied options.  */
   1152   if (richloc.escape_on_output_p ())
   1153     {
   1154       result.m_undecoded_byte_width = width_per_escaped_byte;
   1155       switch (dc.escape_format)
   1156 	{
   1157 	default:
   1158 	  gcc_unreachable ();
   1159 	case DIAGNOSTICS_ESCAPE_FORMAT_UNICODE:
   1160 	  result.m_width_cb = escape_as_unicode_width;
   1161 	  result.m_print_cb = escape_as_unicode_print;
   1162 	  break;
   1163 	case DIAGNOSTICS_ESCAPE_FORMAT_BYTES:
   1164 	  result.m_width_cb = escape_as_bytes_width;
   1165 	  result.m_print_cb = escape_as_bytes_print;
   1166 	  break;
   1167 	}
   1168     }
   1169 
   1170   return result;
   1171 }
   1172 
   1173 /* Implementation of class layout.  */
   1174 
   1175 /* Constructor for class layout.
   1176 
   1177    Filter the ranges from the rich_location to those that we can
   1178    sanely print, populating m_layout_ranges and m_fixit_hints.
   1179    Determine the range of lines that we will print, splitting them
   1180    up into an ordered list of disjoint spans of contiguous line numbers.
   1181    Determine m_x_offset_display, to ensure that the primary caret
   1182    will fit within the max_width provided by the diagnostic_context.  */
   1183 
   1184 layout::layout (diagnostic_context * context,
   1185 		rich_location *richloc,
   1186 		diagnostic_t diagnostic_kind)
   1187 : m_context (context),
   1188   m_pp (context->printer),
   1189   m_policy (make_policy (*context, *richloc)),
   1190   m_primary_loc (richloc->get_range (0)->m_loc),
   1191   m_exploc (richloc->get_expanded_location (0), m_policy,
   1192 	    LOCATION_ASPECT_CARET),
   1193   m_colorizer (context, diagnostic_kind),
   1194   m_colorize_source_p (context->colorize_source_p),
   1195   m_show_labels_p (context->show_labels_p),
   1196   m_show_line_numbers_p (context->show_line_numbers_p),
   1197   m_diagnostic_path_p (diagnostic_kind == DK_DIAGNOSTIC_PATH),
   1198   m_layout_ranges (richloc->get_num_locations ()),
   1199   m_fixit_hints (richloc->get_num_fixit_hints ()),
   1200   m_line_spans (1 + richloc->get_num_locations ()),
   1201   m_linenum_width (0),
   1202   m_x_offset_display (0),
   1203   m_escape_on_output (richloc->escape_on_output_p ())
   1204 {
   1205   for (unsigned int idx = 0; idx < richloc->get_num_locations (); idx++)
   1206     {
   1207       /* This diagnostic printer can only cope with "sufficiently sane" ranges.
   1208 	 Ignore any ranges that are awkward to handle.  */
   1209       const location_range *loc_range = richloc->get_range (idx);
   1210       maybe_add_location_range (loc_range, idx, false);
   1211     }
   1212 
   1213   /* Populate m_fixit_hints, filtering to only those that are in the
   1214      same file.  */
   1215   for (unsigned int i = 0; i < richloc->get_num_fixit_hints (); i++)
   1216     {
   1217       const fixit_hint *hint = richloc->get_fixit_hint (i);
   1218       if (validate_fixit_hint_p (hint))
   1219 	m_fixit_hints.safe_push (hint);
   1220     }
   1221 
   1222   /* Sort m_fixit_hints.  */
   1223   m_fixit_hints.qsort (fixit_cmp);
   1224 
   1225   /* Populate the indicated members.  */
   1226   calculate_line_spans ();
   1227   calculate_linenum_width ();
   1228   calculate_x_offset_display ();
   1229 
   1230   if (context->show_ruler_p)
   1231     show_ruler (m_x_offset_display + m_context->caret_max_width);
   1232 }
   1233 
   1234 
   1235 /* Attempt to add LOC_RANGE to m_layout_ranges, filtering them to
   1236    those that we can sanely print.
   1237 
   1238    ORIGINAL_IDX is the index of LOC_RANGE within its rich_location,
   1239    (for use as extrinsic state by label ranges FIXME).
   1240 
   1241    If RESTRICT_TO_CURRENT_LINE_SPANS is true, then LOC_RANGE is also
   1242    filtered against this layout instance's current line spans: it
   1243    will only be added if the location is fully within the lines
   1244    already specified by other locations.
   1245 
   1246    Return true iff LOC_RANGE was added.  */
   1247 
   1248 bool
   1249 layout::maybe_add_location_range (const location_range *loc_range,
   1250 				  unsigned original_idx,
   1251 				  bool restrict_to_current_line_spans)
   1252 {
   1253   gcc_assert (loc_range);
   1254 
   1255   /* Split the "range" into caret and range information.  */
   1256   source_range src_range = get_range_from_loc (line_table, loc_range->m_loc);
   1257 
   1258   /* Expand the various locations.  */
   1259   expanded_location start
   1260     = linemap_client_expand_location_to_spelling_point
   1261     (src_range.m_start, LOCATION_ASPECT_START);
   1262   expanded_location finish
   1263     = linemap_client_expand_location_to_spelling_point
   1264     (src_range.m_finish, LOCATION_ASPECT_FINISH);
   1265   expanded_location caret
   1266     = linemap_client_expand_location_to_spelling_point
   1267     (loc_range->m_loc, LOCATION_ASPECT_CARET);
   1268 
   1269   /* If any part of the range isn't in the same file as the primary
   1270      location of this diagnostic, ignore the range.  */
   1271   if (start.file != m_exploc.file)
   1272     return false;
   1273   if (finish.file != m_exploc.file)
   1274     return false;
   1275   if (loc_range->m_range_display_kind == SHOW_RANGE_WITH_CARET)
   1276     if (caret.file != m_exploc.file)
   1277       return false;
   1278 
   1279   /* Sanitize the caret location for non-primary ranges.  */
   1280   if (m_layout_ranges.length () > 0)
   1281     if (loc_range->m_range_display_kind == SHOW_RANGE_WITH_CARET)
   1282       if (!compatible_locations_p (loc_range->m_loc, m_primary_loc))
   1283 	/* Discard any non-primary ranges that can't be printed
   1284 	   sanely relative to the primary location.  */
   1285 	return false;
   1286 
   1287   /* Everything is now known to be in the correct source file,
   1288      but it may require further sanitization.  */
   1289   layout_range ri (exploc_with_display_col (start, m_policy,
   1290 					    LOCATION_ASPECT_START),
   1291 		   exploc_with_display_col (finish, m_policy,
   1292 					    LOCATION_ASPECT_FINISH),
   1293 		   loc_range->m_range_display_kind,
   1294 		   exploc_with_display_col (caret, m_policy,
   1295 					    LOCATION_ASPECT_CARET),
   1296 		   original_idx, loc_range->m_label);
   1297 
   1298   /* If we have a range that finishes before it starts (perhaps
   1299      from something built via macro expansion), printing the
   1300      range is likely to be nonsensical.  Also, attempting to do so
   1301      breaks assumptions within the printing code  (PR c/68473).
   1302      Similarly, don't attempt to print ranges if one or both ends
   1303      of the range aren't sane to print relative to the
   1304      primary location (PR c++/70105).  */
   1305   if (start.line > finish.line
   1306       || !compatible_locations_p (src_range.m_start, m_primary_loc)
   1307       || !compatible_locations_p (src_range.m_finish, m_primary_loc))
   1308     {
   1309       /* Is this the primary location?  */
   1310       if (m_layout_ranges.length () == 0)
   1311 	{
   1312 	  /* We want to print the caret for the primary location, but
   1313 	     we must sanitize away m_start and m_finish.  */
   1314 	  ri.m_start = ri.m_caret;
   1315 	  ri.m_finish = ri.m_caret;
   1316 	}
   1317       else
   1318 	/* This is a non-primary range; ignore it.  */
   1319 	return false;
   1320     }
   1321 
   1322   /* Potentially filter to just the lines already specified by other
   1323      locations.  This is for use by gcc_rich_location::add_location_if_nearby.
   1324      The layout ctor doesn't use it, and can't because m_line_spans
   1325      hasn't been set up at that point.  */
   1326   if (restrict_to_current_line_spans)
   1327     {
   1328       if (!will_show_line_p (start.line))
   1329 	return false;
   1330       if (!will_show_line_p (finish.line))
   1331 	return false;
   1332       if (loc_range->m_range_display_kind == SHOW_RANGE_WITH_CARET)
   1333 	if (!will_show_line_p (caret.line))
   1334 	  return false;
   1335     }
   1336 
   1337   /* Passed all the tests; add the range to m_layout_ranges so that
   1338      it will be printed.  */
   1339   m_layout_ranges.safe_push (ri);
   1340   return true;
   1341 }
   1342 
   1343 /* Return true iff ROW is within one of the line spans for this layout.  */
   1344 
   1345 bool
   1346 layout::will_show_line_p (linenum_type row) const
   1347 {
   1348   for (int line_span_idx = 0; line_span_idx < get_num_line_spans ();
   1349        line_span_idx++)
   1350     {
   1351       const line_span *line_span = get_line_span (line_span_idx);
   1352       if (line_span->contains_line_p (row))
   1353 	return true;
   1354     }
   1355   return false;
   1356 }
   1357 
   1358 /* Print a line showing a gap in the line numbers, for showing the boundary
   1359    between two line spans.  */
   1360 
   1361 void
   1362 layout::print_gap_in_line_numbering ()
   1363 {
   1364   gcc_assert (m_show_line_numbers_p);
   1365 
   1366   pp_emit_prefix (m_pp);
   1367 
   1368   for (int i = 0; i < m_linenum_width + 1; i++)
   1369     pp_character (m_pp, '.');
   1370 
   1371   pp_newline (m_pp);
   1372 }
   1373 
   1374 /* Return true iff we should print a heading when starting the
   1375    line span with the given index.  */
   1376 
   1377 bool
   1378 layout::print_heading_for_line_span_index_p (int line_span_idx) const
   1379 {
   1380   /* We print a heading for every change of line span, hence for every
   1381      line span after the initial one.  */
   1382   if (line_span_idx > 0)
   1383     return true;
   1384 
   1385   /* We also do it for the initial span if the primary location of the
   1386      diagnostic is in a different span.  */
   1387   if (m_exploc.line > (int)get_line_span (0)->m_last_line)
   1388     return true;
   1389 
   1390   return false;
   1391 }
   1392 
   1393 /* Get an expanded_location for the first location of interest within
   1394    the given line_span.
   1395    Used when printing a heading to indicate a new line span.  */
   1396 
   1397 expanded_location
   1398 layout::get_expanded_location (const line_span *line_span) const
   1399 {
   1400   /* Whenever possible, use the caret location.  */
   1401   if (line_span->contains_line_p (m_exploc.line))
   1402     return m_exploc;
   1403 
   1404   /* Otherwise, use the start of the first range that's present
   1405      within the line_span.  */
   1406   for (unsigned int i = 0; i < m_layout_ranges.length (); i++)
   1407     {
   1408       const layout_range *lr = &m_layout_ranges[i];
   1409       if (line_span->contains_line_p (lr->m_start.m_line))
   1410 	{
   1411 	  expanded_location exploc = m_exploc;
   1412 	  exploc.line = lr->m_start.m_line;
   1413 	  exploc.column = lr->m_start.m_columns[CU_BYTES];
   1414 	  return exploc;
   1415 	}
   1416     }
   1417 
   1418   /* Otherwise, use the location of the first fixit-hint present within
   1419      the line_span.  */
   1420   for (unsigned int i = 0; i < m_fixit_hints.length (); i++)
   1421     {
   1422       const fixit_hint *hint = m_fixit_hints[i];
   1423       location_t loc = hint->get_start_loc ();
   1424       expanded_location exploc = expand_location (loc);
   1425       if (line_span->contains_line_p (exploc.line))
   1426 	return exploc;
   1427     }
   1428 
   1429   /* It should not be possible to have a line span that didn't
   1430      contain any of the layout_range or fixit_hint instances.  */
   1431   gcc_unreachable ();
   1432   return m_exploc;
   1433 }
   1434 
   1435 /* Determine if HINT is meaningful to print within this layout.  */
   1436 
   1437 bool
   1438 layout::validate_fixit_hint_p (const fixit_hint *hint)
   1439 {
   1440   if (LOCATION_FILE (hint->get_start_loc ()) != m_exploc.file)
   1441     return false;
   1442   if (LOCATION_FILE (hint->get_next_loc ()) != m_exploc.file)
   1443     return false;
   1444 
   1445   return true;
   1446 }
   1447 
   1448 /* Determine the range of lines affected by HINT.
   1449    This assumes that HINT has already been filtered by
   1450    validate_fixit_hint_p, and so affects the correct source file.  */
   1451 
   1452 static line_span
   1453 get_line_span_for_fixit_hint (const fixit_hint *hint)
   1454 {
   1455   gcc_assert (hint);
   1456 
   1457   int start_line = LOCATION_LINE (hint->get_start_loc ());
   1458 
   1459   /* For line-insertion fix-it hints, add the previous line to the
   1460      span, to give the user more context on the proposed change.  */
   1461   if (hint->ends_with_newline_p ())
   1462     if (start_line > 1)
   1463       start_line--;
   1464 
   1465   return line_span (start_line,
   1466 		    LOCATION_LINE (hint->get_next_loc ()));
   1467 }
   1468 
   1469 /* We want to print the pertinent source code at a diagnostic.  The
   1470    rich_location can contain multiple locations.  This will have been
   1471    filtered into m_exploc (the caret for the primary location) and
   1472    m_layout_ranges, for those ranges within the same source file.
   1473 
   1474    We will print a subset of the lines within the source file in question,
   1475    as a collection of "spans" of lines.
   1476 
   1477    This function populates m_line_spans with an ordered, disjoint list of
   1478    the line spans of interest.
   1479 
   1480    Printing a gap between line spans takes one line, so, when printing
   1481    line numbers, we allow a gap of up to one line between spans when
   1482    merging, since it makes more sense to print the source line rather than a
   1483    "gap-in-line-numbering" line.  When not printing line numbers, it's
   1484    better to be more explicit about what's going on, so keeping them as
   1485    separate spans is preferred.
   1486 
   1487    For example, if the primary range is on lines 8-10, with secondary ranges
   1488    covering lines 5-6 and lines 13-15:
   1489 
   1490      004
   1491      005                   |RANGE 1
   1492      006                   |RANGE 1
   1493      007
   1494      008  |PRIMARY RANGE
   1495      009  |PRIMARY CARET
   1496      010  |PRIMARY RANGE
   1497      011
   1498      012
   1499      013                                |RANGE 2
   1500      014                                |RANGE 2
   1501      015                                |RANGE 2
   1502      016
   1503 
   1504    With line numbering on, we want two spans: lines 5-10 and lines 13-15.
   1505 
   1506    With line numbering off (with span headers), we want three spans: lines 5-6,
   1507    lines 8-10, and lines 13-15.  */
   1508 
   1509 void
   1510 layout::calculate_line_spans ()
   1511 {
   1512   /* This should only be called once, by the ctor.  */
   1513   gcc_assert (m_line_spans.length () == 0);
   1514 
   1515   /* Populate tmp_spans with individual spans, for each of
   1516      m_exploc, and for m_layout_ranges.  */
   1517   auto_vec<line_span> tmp_spans (1 + m_layout_ranges.length ());
   1518   tmp_spans.safe_push (line_span (m_exploc.line, m_exploc.line));
   1519   for (unsigned int i = 0; i < m_layout_ranges.length (); i++)
   1520     {
   1521       const layout_range *lr = &m_layout_ranges[i];
   1522       gcc_assert (lr->m_start.m_line <= lr->m_finish.m_line);
   1523       tmp_spans.safe_push (line_span (lr->m_start.m_line,
   1524 				      lr->m_finish.m_line));
   1525     }
   1526 
   1527   /* Also add spans for any fix-it hints, in case they cover other lines.  */
   1528   for (unsigned int i = 0; i < m_fixit_hints.length (); i++)
   1529     {
   1530       const fixit_hint *hint = m_fixit_hints[i];
   1531       gcc_assert (hint);
   1532       tmp_spans.safe_push (get_line_span_for_fixit_hint (hint));
   1533     }
   1534 
   1535   /* Sort them.  */
   1536   tmp_spans.qsort(line_span::comparator);
   1537 
   1538   /* Now iterate through tmp_spans, copying into m_line_spans, and
   1539      combining where possible.  */
   1540   gcc_assert (tmp_spans.length () > 0);
   1541   m_line_spans.safe_push (tmp_spans[0]);
   1542   for (unsigned int i = 1; i < tmp_spans.length (); i++)
   1543     {
   1544       line_span *current = &m_line_spans[m_line_spans.length () - 1];
   1545       const line_span *next = &tmp_spans[i];
   1546       gcc_assert (next->m_first_line >= current->m_first_line);
   1547       const int merger_distance = m_show_line_numbers_p ? 1 : 0;
   1548       if ((linenum_arith_t)next->m_first_line
   1549 	  <= (linenum_arith_t)current->m_last_line + 1 + merger_distance)
   1550 	{
   1551 	  /* We can merge them. */
   1552 	  if (next->m_last_line > current->m_last_line)
   1553 	    current->m_last_line = next->m_last_line;
   1554 	}
   1555       else
   1556 	{
   1557 	  /* No merger possible.  */
   1558 	  m_line_spans.safe_push (*next);
   1559 	}
   1560     }
   1561 
   1562   /* Verify the result, in m_line_spans.  */
   1563   gcc_assert (m_line_spans.length () > 0);
   1564   for (unsigned int i = 1; i < m_line_spans.length (); i++)
   1565     {
   1566       const line_span *prev = &m_line_spans[i - 1];
   1567       const line_span *next = &m_line_spans[i];
   1568       /* The individual spans must be sane.  */
   1569       gcc_assert (prev->m_first_line <= prev->m_last_line);
   1570       gcc_assert (next->m_first_line <= next->m_last_line);
   1571       /* The spans must be ordered.  */
   1572       gcc_assert (prev->m_first_line < next->m_first_line);
   1573       /* There must be a gap of at least one line between separate spans.  */
   1574       gcc_assert ((prev->m_last_line + 1) < next->m_first_line);
   1575     }
   1576 }
   1577 
   1578 /* Determine how many display columns need to be reserved for line numbers,
   1579    based on the largest line number that will be needed, and populate
   1580    m_linenum_width.  */
   1581 
   1582 void
   1583 layout::calculate_linenum_width ()
   1584 {
   1585   gcc_assert (m_line_spans.length () > 0);
   1586   const line_span *last_span = &m_line_spans[m_line_spans.length () - 1];
   1587   int highest_line = last_span->m_last_line;
   1588   if (highest_line < 0)
   1589     highest_line = 0;
   1590   m_linenum_width = num_digits (highest_line);
   1591   /* If we're showing jumps in the line-numbering, allow at least 3 chars.  */
   1592   if (m_line_spans.length () > 1)
   1593     m_linenum_width = MAX (m_linenum_width, 3);
   1594   /* If there's a minimum margin width, apply it (subtracting 1 for the space
   1595      after the line number.  */
   1596   m_linenum_width = MAX (m_linenum_width, m_context->min_margin_width - 1);
   1597 }
   1598 
   1599 /* Calculate m_x_offset_display, which improves readability in case the source
   1600    line of interest is longer than the user's display.  All lines output will be
   1601    shifted to the left (so that their beginning is no longer displayed) by
   1602    m_x_offset_display display columns, so that the caret is in a reasonable
   1603    location.  */
   1604 
   1605 void
   1606 layout::calculate_x_offset_display ()
   1607 {
   1608   m_x_offset_display = 0;
   1609 
   1610   const int max_width = m_context->caret_max_width;
   1611   if (!max_width)
   1612     {
   1613       /* Nothing to do, the width is not capped.  */
   1614       return;
   1615     }
   1616 
   1617   const char_span line = location_get_source_line (m_exploc.file,
   1618 						   m_exploc.line);
   1619   if (!line)
   1620     {
   1621       /* Nothing to do, we couldn't find the source line.  */
   1622       return;
   1623     }
   1624   int caret_display_column = m_exploc.m_display_col;
   1625   const int line_bytes
   1626     = get_line_bytes_without_trailing_whitespace (line.get_buffer (),
   1627 						  line.length ());
   1628   int eol_display_column
   1629     = cpp_display_width (line.get_buffer (), line_bytes, m_policy);
   1630   if (caret_display_column > eol_display_column
   1631       || !caret_display_column)
   1632     {
   1633       /* This does not make sense, so don't try to do anything in this case.  */
   1634       return;
   1635     }
   1636 
   1637   /* Adjust caret and eol positions to include the left margin.  If we are
   1638      outputting line numbers, then the left margin is equal to m_linenum_width
   1639      plus three for the " | " which follows it.  Otherwise the left margin width
   1640      is equal to 1, because layout::print_source_line() will prefix each line
   1641      with a space.  */
   1642   const int source_display_cols = eol_display_column;
   1643   int left_margin_size = 1;
   1644   if (m_show_line_numbers_p)
   1645       left_margin_size = m_linenum_width + 3;
   1646   caret_display_column += left_margin_size;
   1647   eol_display_column += left_margin_size;
   1648 
   1649   if (eol_display_column <= max_width)
   1650     {
   1651       /* Nothing to do, everything fits in the display.  */
   1652       return;
   1653     }
   1654 
   1655   /* The line is too long for the display.  Calculate an offset such that the
   1656      caret is not too close to the right edge of the screen.  It will be
   1657      CARET_LINE_MARGIN display columns from the right edge, unless it is closer
   1658      than that to the end of the source line anyway.  */
   1659   int right_margin_size = CARET_LINE_MARGIN;
   1660   right_margin_size = MIN (eol_display_column - caret_display_column,
   1661 			   right_margin_size);
   1662   if (right_margin_size + left_margin_size >= max_width)
   1663     {
   1664       /* The max_width is very small, so anything we try to do will not be very
   1665 	 effective; just punt in this case and output with no offset.  */
   1666       return;
   1667     }
   1668   const int max_caret_display_column = max_width - right_margin_size;
   1669   if (caret_display_column > max_caret_display_column)
   1670     {
   1671       m_x_offset_display = caret_display_column - max_caret_display_column;
   1672       /* Make sure we don't offset the line into oblivion.  */
   1673       static const int min_cols_visible = 2;
   1674       if (source_display_cols - m_x_offset_display < min_cols_visible)
   1675 	m_x_offset_display = 0;
   1676     }
   1677 }
   1678 
   1679 /* Print line ROW of source code, potentially colorized at any ranges, and
   1680    return the line bounds.  LINE is the source line (not necessarily
   1681    0-terminated) and LINE_BYTES is its length in bytes.  In order to handle both
   1682    colorization and tab expansion, this function tracks the line position in
   1683    both byte and display column units.  */
   1684 
   1685 line_bounds
   1686 layout::print_source_line (linenum_type row, const char *line, int line_bytes)
   1687 {
   1688   m_colorizer.set_normal_text ();
   1689 
   1690   pp_emit_prefix (m_pp);
   1691   if (m_show_line_numbers_p)
   1692     {
   1693       int width = num_digits (row);
   1694       for (int i = 0; i < m_linenum_width - width; i++)
   1695 	pp_space (m_pp);
   1696       pp_printf (m_pp, "%i | ", row);
   1697     }
   1698   else
   1699     pp_space (m_pp);
   1700 
   1701   /* We will stop printing the source line at any trailing whitespace.  */
   1702   line_bytes = get_line_bytes_without_trailing_whitespace (line,
   1703 							   line_bytes);
   1704 
   1705   /* This object helps to keep track of which display column we are at, which is
   1706      necessary for computing the line bounds in display units, for doing
   1707      tab expansion, and for implementing m_x_offset_display.  */
   1708   cpp_display_width_computation dw (line, line_bytes, m_policy);
   1709 
   1710   /* Skip the first m_x_offset_display display columns.  In case the leading
   1711      portion that will be skipped ends with a character with wcwidth > 1, then
   1712      it is possible we skipped too much, so account for that by padding with
   1713      spaces.  Note that this does the right thing too in case a tab was the last
   1714      character to be skipped over; the tab is effectively replaced by the
   1715      correct number of trailing spaces needed to offset by the desired number of
   1716      display columns.  */
   1717   for (int skipped_display_cols = dw.advance_display_cols (m_x_offset_display);
   1718        skipped_display_cols > m_x_offset_display; --skipped_display_cols)
   1719     pp_space (m_pp);
   1720 
   1721   /* Print the line and compute the line_bounds.  */
   1722   line_bounds lbounds;
   1723   while (!dw.done ())
   1724     {
   1725       /* Assuming colorization is enabled for the caret and underline
   1726 	 characters, we may also colorize the associated characters
   1727 	 within the source line.
   1728 
   1729 	 For frontends that generate range information, we color the
   1730 	 associated characters in the source line the same as the
   1731 	 carets and underlines in the annotation line, to make it easier
   1732 	 for the reader to see the pertinent code.
   1733 
   1734 	 For frontends that only generate carets, we don't colorize the
   1735 	 characters above them, since this would look strange (e.g.
   1736 	 colorizing just the first character in a token).  */
   1737       if (m_colorize_source_p)
   1738 	{
   1739 	  bool in_range_p;
   1740 	  point_state state;
   1741 	  const int start_byte_col = dw.bytes_processed () + 1;
   1742 	  in_range_p = get_state_at_point (row, start_byte_col,
   1743 					   0, INT_MAX,
   1744 					   CU_BYTES,
   1745 					   &state);
   1746 	  if (in_range_p)
   1747 	    m_colorizer.set_range (state.range_idx);
   1748 	  else
   1749 	    m_colorizer.set_normal_text ();
   1750 	}
   1751 
   1752       /* Get the display width of the next character to be output, expanding
   1753 	 tabs and replacing some control bytes with spaces as necessary.  */
   1754       const char *c = dw.next_byte ();
   1755       const int start_disp_col = dw.display_cols_processed () + 1;
   1756       cpp_decoded_char cp;
   1757       const int this_display_width = dw.process_next_codepoint (&cp);
   1758       if (*c == '\t')
   1759 	{
   1760 	  /* The returned display width is the number of spaces into which the
   1761 	     tab should be expanded.  */
   1762 	  for (int i = 0; i != this_display_width; ++i)
   1763 	    pp_space (m_pp);
   1764 	  continue;
   1765 	}
   1766 
   1767       /* We have a (possibly multibyte) character to output; update the line
   1768 	 bounds if it is not whitespace.  */
   1769       if (*c != ' ')
   1770 	{
   1771 	  lbounds.m_last_non_ws_disp_col = dw.display_cols_processed ();
   1772 	  if (lbounds.m_first_non_ws_disp_col == INT_MAX)
   1773 	    lbounds.m_first_non_ws_disp_col = start_disp_col;
   1774 	}
   1775 
   1776       /* Output the character.  */
   1777       m_policy.m_print_cb (m_pp, cp);
   1778       c = dw.next_byte ();
   1779     }
   1780   print_newline ();
   1781   return lbounds;
   1782 }
   1783 
   1784 /* Determine if we should print an annotation line for ROW.
   1785    i.e. if any of m_layout_ranges contains ROW.  */
   1786 
   1787 bool
   1788 layout::should_print_annotation_line_p (linenum_type row) const
   1789 {
   1790   layout_range *range;
   1791   int i;
   1792   FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
   1793     {
   1794       if (range->m_range_display_kind == SHOW_LINES_WITHOUT_RANGE)
   1795 	return false;
   1796       if (range->intersects_line_p (row))
   1797 	return true;
   1798     }
   1799   return false;
   1800 }
   1801 
   1802 /* Begin an annotation line.  If m_show_line_numbers_p, print the left
   1803    margin, which is empty for annotation lines.  Otherwise, do nothing.  */
   1804 
   1805 void
   1806 layout::start_annotation_line (char margin_char) const
   1807 {
   1808   pp_emit_prefix (m_pp);
   1809   if (m_show_line_numbers_p)
   1810     {
   1811       /* Print the margin.  If MARGIN_CHAR != ' ', then print up to 3
   1812 	 of it, right-aligned, padded with spaces.  */
   1813       int i;
   1814       for (i = 0; i < m_linenum_width - 3; i++)
   1815 	pp_space (m_pp);
   1816       for (; i < m_linenum_width; i++)
   1817 	pp_character (m_pp, margin_char);
   1818       pp_string (m_pp, " |");
   1819     }
   1820 }
   1821 
   1822 /* Print a line consisting of the caret/underlines for the given
   1823    source line.  */
   1824 
   1825 void
   1826 layout::print_annotation_line (linenum_type row, const line_bounds lbounds)
   1827 {
   1828   int x_bound = get_x_bound_for_row (row, m_exploc.m_display_col,
   1829 				     lbounds.m_last_non_ws_disp_col);
   1830 
   1831   start_annotation_line ();
   1832   pp_space (m_pp);
   1833 
   1834   for (int column = 1 + m_x_offset_display; column < x_bound; column++)
   1835     {
   1836       bool in_range_p;
   1837       point_state state;
   1838       in_range_p = get_state_at_point (row, column,
   1839 				       lbounds.m_first_non_ws_disp_col,
   1840 				       lbounds.m_last_non_ws_disp_col,
   1841 				       CU_DISPLAY_COLS,
   1842 				       &state);
   1843       if (in_range_p)
   1844 	{
   1845 	  /* Within a range.  Draw either the caret or an underline.  */
   1846 	  m_colorizer.set_range (state.range_idx);
   1847 	  if (state.draw_caret_p)
   1848 	    {
   1849 	      /* Draw the caret.  */
   1850 	      char caret_char;
   1851 	      if (state.range_idx < rich_location::STATICALLY_ALLOCATED_RANGES)
   1852 		caret_char = m_context->caret_chars[state.range_idx];
   1853 	      else
   1854 		caret_char = '^';
   1855 	      pp_character (m_pp, caret_char);
   1856 	    }
   1857 	  else
   1858 	    pp_character (m_pp, '~');
   1859 	}
   1860       else
   1861 	{
   1862 	  /* Not in a range.  */
   1863 	  m_colorizer.set_normal_text ();
   1864 	  pp_character (m_pp, ' ');
   1865 	}
   1866     }
   1867   print_newline ();
   1868 }
   1869 
   1870 /* Implementation detail of layout::print_any_labels.
   1871 
   1872    A label within the given row of source.  */
   1873 
   1874 class line_label
   1875 {
   1876 public:
   1877   line_label (const cpp_char_column_policy &policy,
   1878 	      int state_idx, int column,
   1879 	      label_text text)
   1880   : m_state_idx (state_idx), m_column (column),
   1881     m_text (text), m_label_line (0), m_has_vbar (true)
   1882   {
   1883     const int bytes = strlen (text.m_buffer);
   1884     m_display_width = cpp_display_width (text.m_buffer, bytes, policy);
   1885   }
   1886 
   1887   /* Sorting is primarily by column, then by state index.  */
   1888   static int comparator (const void *p1, const void *p2)
   1889   {
   1890     const line_label *ll1 = (const line_label *)p1;
   1891     const line_label *ll2 = (const line_label *)p2;
   1892     int column_cmp = compare (ll1->m_column, ll2->m_column);
   1893     if (column_cmp)
   1894       return column_cmp;
   1895     /* Order by reverse state index, so that labels are printed
   1896        in order of insertion into the rich_location when the
   1897        sorted list is walked backwards.  */
   1898     return -compare (ll1->m_state_idx, ll2->m_state_idx);
   1899   }
   1900 
   1901   int m_state_idx;
   1902   int m_column;
   1903   label_text m_text;
   1904   size_t m_display_width;
   1905   int m_label_line;
   1906   bool m_has_vbar;
   1907 };
   1908 
   1909 /* Print any labels in this row.  */
   1910 void
   1911 layout::print_any_labels (linenum_type row)
   1912 {
   1913   int i;
   1914   auto_vec<line_label> labels;
   1915 
   1916   /* Gather the labels that are to be printed into "labels".  */
   1917   {
   1918     layout_range *range;
   1919     FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
   1920       {
   1921 	/* Most ranges don't have labels, so reject this first.  */
   1922 	if (range->m_label == NULL)
   1923 	  continue;
   1924 
   1925 	/* The range's caret must be on this line.  */
   1926 	if (range->m_caret.m_line != row)
   1927 	  continue;
   1928 
   1929 	/* Reject labels that aren't fully visible due to clipping
   1930 	   by m_x_offset_display.  */
   1931 	const int disp_col = range->m_caret.m_columns[CU_DISPLAY_COLS];
   1932 	if (disp_col <= m_x_offset_display)
   1933 	  continue;
   1934 
   1935 	label_text text;
   1936 	text = range->m_label->get_text (range->m_original_idx);
   1937 
   1938 	/* Allow for labels that return NULL from their get_text
   1939 	   implementation (so e.g. such labels can control their own
   1940 	   visibility).  */
   1941 	if (text.m_buffer == NULL)
   1942 	  continue;
   1943 
   1944 	labels.safe_push (line_label (m_policy, i, disp_col, text));
   1945       }
   1946   }
   1947 
   1948   /* Bail out if there are no labels on this row.  */
   1949   if (labels.length () == 0)
   1950     return;
   1951 
   1952   /* Sort them.  */
   1953   labels.qsort(line_label::comparator);
   1954 
   1955   /* Figure out how many "label lines" we need, and which
   1956      one each label is printed in.
   1957 
   1958      For example, if the labels aren't too densely packed,
   1959      we can fit them on the same line, giving two "label lines":
   1960 
   1961        foo + bar
   1962        ~~~   ~~~
   1963        |     |        : label line 0
   1964        l0    l1       : label line 1
   1965 
   1966      If they would touch each other or overlap, then we need
   1967      additional "label lines":
   1968 
   1969        foo + bar
   1970        ~~~   ~~~
   1971        |     |             : label line 0
   1972        |     label 1       : label line 1
   1973        label 0             : label line 2
   1974 
   1975      Place the final label on label line 1, and work backwards, adding
   1976      label lines as needed.
   1977 
   1978      If multiple labels are at the same place, put them on separate
   1979      label lines:
   1980 
   1981        foo + bar
   1982            ^               : label line 0
   1983            |               : label line 1
   1984            label 0         : label line 2
   1985            label 1         : label line 3.  */
   1986 
   1987   int max_label_line = 1;
   1988   {
   1989     int next_column = INT_MAX;
   1990     line_label *label;
   1991     FOR_EACH_VEC_ELT_REVERSE (labels, i, label)
   1992       {
   1993 	/* Would this label "touch" or overlap the next label?  */
   1994 	if (label->m_column + label->m_display_width >= (size_t)next_column)
   1995 	  {
   1996 	    max_label_line++;
   1997 
   1998 	    /* If we've already seen labels with the same column, suppress the
   1999 	       vertical bar for subsequent ones in this backwards iteration;
   2000 	       hence only the one with the highest label_line has m_has_vbar set.  */
   2001 	    if (label->m_column == next_column)
   2002 	      label->m_has_vbar = false;
   2003 	  }
   2004 
   2005 	label->m_label_line = max_label_line;
   2006 	next_column = label->m_column;
   2007       }
   2008   }
   2009 
   2010   /* Print the "label lines".  For each label within the line, print
   2011      either a vertical bar ('|') for the labels that are lower down, or the
   2012      labels themselves once we've reached their line.  */
   2013   {
   2014     for (int label_line = 0; label_line <= max_label_line; label_line++)
   2015       {
   2016 	start_annotation_line ();
   2017 	pp_space (m_pp);
   2018 	int column = 1 + m_x_offset_display;
   2019 	line_label *label;
   2020 	FOR_EACH_VEC_ELT (labels, i, label)
   2021 	  {
   2022 	    if (label_line > label->m_label_line)
   2023 	      /* We've printed all the labels for this label line.  */
   2024 	      break;
   2025 
   2026 	    if (label_line == label->m_label_line)
   2027 	      {
   2028 		gcc_assert (column <= label->m_column);
   2029 		move_to_column (&column, label->m_column, true);
   2030 		/* Colorize the text, unless it's for events in a
   2031 		   diagnostic_path.  */
   2032 		if (!m_diagnostic_path_p)
   2033 		  m_colorizer.set_range (label->m_state_idx);
   2034 		pp_string (m_pp, label->m_text.m_buffer);
   2035 		m_colorizer.set_normal_text ();
   2036 		column += label->m_display_width;
   2037 	      }
   2038 	    else if (label->m_has_vbar)
   2039 	      {
   2040 		gcc_assert (column <= label->m_column);
   2041 		move_to_column (&column, label->m_column, true);
   2042 		m_colorizer.set_range (label->m_state_idx);
   2043 		pp_character (m_pp, '|');
   2044 		m_colorizer.set_normal_text ();
   2045 		column++;
   2046 	      }
   2047 	  }
   2048 	print_newline ();
   2049       }
   2050     }
   2051 
   2052   /* Clean up.  */
   2053   {
   2054     line_label *label;
   2055     FOR_EACH_VEC_ELT (labels, i, label)
   2056       label->m_text.maybe_free ();
   2057   }
   2058 }
   2059 
   2060 /* If there are any fixit hints inserting new lines before source line ROW,
   2061    print them.
   2062 
   2063    They are printed on lines of their own, before the source line
   2064    itself, with a leading '+'.  */
   2065 
   2066 void
   2067 layout::print_leading_fixits (linenum_type row)
   2068 {
   2069   for (unsigned int i = 0; i < m_fixit_hints.length (); i++)
   2070     {
   2071       const fixit_hint *hint = m_fixit_hints[i];
   2072 
   2073       if (!hint->ends_with_newline_p ())
   2074 	/* Not a newline fixit; print it in print_trailing_fixits.  */
   2075 	continue;
   2076 
   2077       gcc_assert (hint->insertion_p ());
   2078 
   2079       if (hint->affects_line_p (m_exploc.file, row))
   2080 	{
   2081 	  /* Printing the '+' with normal colorization
   2082 	     and the inserted line with "insert" colorization
   2083 	     helps them stand out from each other, and from
   2084 	     the surrounding text.  */
   2085 	  m_colorizer.set_normal_text ();
   2086 	  start_annotation_line ('+');
   2087 	  pp_character (m_pp, '+');
   2088 	  m_colorizer.set_fixit_insert ();
   2089 	  /* Print all but the trailing newline of the fix-it hint.
   2090 	     We have to print the newline separately to avoid
   2091 	     getting additional pp prefixes printed.  */
   2092 	  for (size_t i = 0; i < hint->get_length () - 1; i++)
   2093 	    pp_character (m_pp, hint->get_string ()[i]);
   2094 	  m_colorizer.set_normal_text ();
   2095 	  pp_newline (m_pp);
   2096 	}
   2097     }
   2098 }
   2099 
   2100 /* Subroutine of layout::print_trailing_fixits.
   2101 
   2102    Determine if the annotation line printed for LINE contained
   2103    the exact range from START_COLUMN to FINISH_COLUMN (in display units).  */
   2104 
   2105 bool
   2106 layout::annotation_line_showed_range_p (linenum_type line, int start_column,
   2107 					int finish_column) const
   2108 {
   2109   layout_range *range;
   2110   int i;
   2111   FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
   2112     if (range->m_start.m_line == line
   2113 	&& range->m_start.m_columns[CU_DISPLAY_COLS] == start_column
   2114 	&& range->m_finish.m_line == line
   2115 	&& range->m_finish.m_columns[CU_DISPLAY_COLS] == finish_column)
   2116       return true;
   2117   return false;
   2118 }
   2119 
   2120 /* Classes for printing trailing fix-it hints i.e. those that
   2121    don't add new lines.
   2122 
   2123    For insertion, these can look like:
   2124 
   2125      new_text
   2126 
   2127    For replacement, these can look like:
   2128 
   2129      ------------- : underline showing affected range
   2130      new_text
   2131 
   2132    For deletion, these can look like:
   2133 
   2134      ------------- : underline showing affected range
   2135 
   2136    This can become confusing if they overlap, and so we need
   2137    to do some preprocessing to decide what to print.
   2138    We use the list of fixit_hint instances affecting the line
   2139    to build a list of "correction" instances, and print the
   2140    latter.
   2141 
   2142    For example, consider a set of fix-its for converting
   2143    a C-style cast to a C++ const_cast.
   2144 
   2145    Given:
   2146 
   2147    ..000000000111111111122222222223333333333.
   2148    ..123456789012345678901234567890123456789.
   2149      foo *f = (foo *)ptr->field;
   2150                           ^~~~~
   2151 
   2152    and the fix-it hints:
   2153      - replace col 10 (the open paren) with "const_cast<"
   2154      - replace col 16 (the close paren) with "> ("
   2155      - insert ")" before col 27
   2156 
   2157    then we would get odd-looking output:
   2158 
   2159      foo *f = (foo *)ptr->field;
   2160                           ^~~~~
   2161               -
   2162               const_cast<
   2163                     -
   2164                     > (        )
   2165 
   2166    It would be better to detect when fixit hints are going to
   2167    overlap (those that require new lines), and to consolidate
   2168    the printing of such fixits, giving something like:
   2169 
   2170      foo *f = (foo *)ptr->field;
   2171                           ^~~~~
   2172               -----------------
   2173               const_cast<foo *> (ptr->field)
   2174 
   2175    This works by detecting when the printing would overlap, and
   2176    effectively injecting no-op replace hints into the gaps between
   2177    such fix-its, so that the printing joins up.
   2178 
   2179    In the above example, the overlap of:
   2180      - replace col 10 (the open paren) with "const_cast<"
   2181    and:
   2182      - replace col 16 (the close paren) with "> ("
   2183    is fixed by injecting a no-op:
   2184      - replace cols 11-15 with themselves ("foo *")
   2185    and consolidating these, making:
   2186      - replace cols 10-16 with "const_cast<" + "foo *" + "> ("
   2187    i.e.:
   2188      - replace cols 10-16 with "const_cast<foo *> ("
   2189 
   2190    This overlaps with the final fix-it hint:
   2191      - insert ")" before col 27
   2192    and so we repeat the consolidation process, by injecting
   2193    a no-op:
   2194      - replace cols 17-26 with themselves ("ptr->field")
   2195    giving:
   2196      - replace cols 10-26 with "const_cast<foo *> (" + "ptr->field" + ")"
   2197    i.e.:
   2198      - replace cols 10-26 with "const_cast<foo *> (ptr->field)"
   2199 
   2200    and is thus printed as desired.  */
   2201 
   2202 /* A range of (byte or display) columns within a line.  */
   2203 
   2204 class column_range
   2205 {
   2206 public:
   2207   column_range (int start_, int finish_) : start (start_), finish (finish_)
   2208   {
   2209     /* We must have either a range, or an insertion.  */
   2210     gcc_assert (start <= finish || finish == start - 1);
   2211   }
   2212 
   2213   bool operator== (const column_range &other) const
   2214   {
   2215     return start == other.start && finish == other.finish;
   2216   }
   2217 
   2218   int start;
   2219   int finish;
   2220 };
   2221 
   2222 /* Get the range of bytes or display columns that HINT would affect.  */
   2223 static column_range
   2224 get_affected_range (const cpp_char_column_policy &policy,
   2225 		    const fixit_hint *hint, enum column_unit col_unit)
   2226 {
   2227   expanded_location exploc_start = expand_location (hint->get_start_loc ());
   2228   expanded_location exploc_finish = expand_location (hint->get_next_loc ());
   2229   --exploc_finish.column;
   2230 
   2231   int start_column;
   2232   int finish_column;
   2233   if (col_unit == CU_DISPLAY_COLS)
   2234     {
   2235       start_column = location_compute_display_column (exploc_start, policy);
   2236       if (hint->insertion_p ())
   2237 	finish_column = start_column - 1;
   2238       else
   2239 	finish_column = location_compute_display_column (exploc_finish, policy);
   2240     }
   2241   else
   2242     {
   2243       start_column = exploc_start.column;
   2244       finish_column = exploc_finish.column;
   2245     }
   2246   return column_range (start_column, finish_column);
   2247 }
   2248 
   2249 /* Get the range of display columns that would be printed for HINT.  */
   2250 
   2251 static column_range
   2252 get_printed_columns (const cpp_char_column_policy &policy,
   2253 		     const fixit_hint *hint)
   2254 {
   2255   expanded_location exploc = expand_location (hint->get_start_loc ());
   2256   int start_column = location_compute_display_column (exploc, policy);
   2257   int hint_width = cpp_display_width (hint->get_string (), hint->get_length (),
   2258 				      policy);
   2259   int final_hint_column = start_column + hint_width - 1;
   2260   if (hint->insertion_p ())
   2261     {
   2262       return column_range (start_column, final_hint_column);
   2263     }
   2264   else
   2265     {
   2266       exploc = expand_location (hint->get_next_loc ());
   2267       --exploc.column;
   2268       int finish_column = location_compute_display_column (exploc, policy);
   2269       return column_range (start_column,
   2270 			   MAX (finish_column, final_hint_column));
   2271     }
   2272 }
   2273 
   2274 /* A correction on a particular line.
   2275    This describes a plan for how to print one or more fixit_hint
   2276    instances that affected the line, potentially consolidating hints
   2277    into corrections to make the result easier for the user to read.  */
   2278 
   2279 class correction
   2280 {
   2281 public:
   2282   correction (column_range affected_bytes,
   2283 	      column_range affected_columns,
   2284 	      column_range printed_columns,
   2285 	      const char *new_text, size_t new_text_len,
   2286 	      const cpp_char_column_policy &policy)
   2287   : m_affected_bytes (affected_bytes),
   2288     m_affected_columns (affected_columns),
   2289     m_printed_columns (printed_columns),
   2290     m_text (xstrdup (new_text)),
   2291     m_byte_length (new_text_len),
   2292     m_policy (policy),
   2293     m_alloc_sz (new_text_len + 1)
   2294   {
   2295     compute_display_cols ();
   2296   }
   2297 
   2298   ~correction () { free (m_text); }
   2299 
   2300   bool insertion_p () const
   2301   {
   2302     return m_affected_bytes.start == m_affected_bytes.finish + 1;
   2303   }
   2304 
   2305   void ensure_capacity (size_t len);
   2306   void ensure_terminated ();
   2307 
   2308   void compute_display_cols ()
   2309   {
   2310     m_display_cols = cpp_display_width (m_text, m_byte_length, m_policy);
   2311   }
   2312 
   2313   void overwrite (int dst_offset, const char_span &src_span)
   2314   {
   2315     gcc_assert (dst_offset >= 0);
   2316     gcc_assert (dst_offset + src_span.length () < m_alloc_sz);
   2317     memcpy (m_text + dst_offset, src_span.get_buffer (),
   2318 	    src_span.length ());
   2319   }
   2320 
   2321   /* If insert, then start: the column before which the text
   2322      is to be inserted, and finish is offset by the length of
   2323      the replacement.
   2324      If replace, then the range of columns affected.  */
   2325   column_range m_affected_bytes;
   2326   column_range m_affected_columns;
   2327 
   2328   /* If insert, then start: the column before which the text
   2329      is to be inserted, and finish is offset by the length of
   2330      the replacement.
   2331      If replace, then the range of columns affected.  */
   2332   column_range m_printed_columns;
   2333 
   2334   /* The text to be inserted/used as replacement.  */
   2335   char *m_text;
   2336   size_t m_byte_length; /* Not including null-terminator.  */
   2337   int m_display_cols;
   2338   const cpp_char_column_policy &m_policy;
   2339   size_t m_alloc_sz;
   2340 };
   2341 
   2342 /* Ensure that m_text can hold a string of length LEN
   2343    (plus 1 for 0-termination).  */
   2344 
   2345 void
   2346 correction::ensure_capacity (size_t len)
   2347 {
   2348   /* Allow 1 extra byte for 0-termination.  */
   2349   if (m_alloc_sz < (len + 1))
   2350     {
   2351       size_t new_alloc_sz = (len + 1) * 2;
   2352       m_text = (char *)xrealloc (m_text, new_alloc_sz);
   2353       m_alloc_sz = new_alloc_sz;
   2354     }
   2355 }
   2356 
   2357 /* Ensure that m_text is 0-terminated.  */
   2358 
   2359 void
   2360 correction::ensure_terminated ()
   2361 {
   2362   /* 0-terminate the buffer.  */
   2363   gcc_assert (m_byte_length < m_alloc_sz);
   2364   m_text[m_byte_length] = '\0';
   2365 }
   2366 
   2367 /* A list of corrections affecting a particular line.
   2368    This is used by layout::print_trailing_fixits for planning
   2369    how to print the fix-it hints affecting the line.  */
   2370 
   2371 class line_corrections
   2372 {
   2373 public:
   2374   line_corrections (const char_display_policy &policy,
   2375 		    const char *filename,
   2376 		    linenum_type row)
   2377   : m_policy (policy), m_filename (filename), m_row (row)
   2378   {}
   2379   ~line_corrections ();
   2380 
   2381   void add_hint (const fixit_hint *hint);
   2382 
   2383   const char_display_policy &m_policy;
   2384   const char *m_filename;
   2385   linenum_type m_row;
   2386   auto_vec <correction *> m_corrections;
   2387 };
   2388 
   2389 /* struct line_corrections.  */
   2390 
   2391 line_corrections::~line_corrections ()
   2392 {
   2393   unsigned i;
   2394   correction *c;
   2395   FOR_EACH_VEC_ELT (m_corrections, i, c)
   2396     delete c;
   2397 }
   2398 
   2399 /* A struct wrapping a particular source line, allowing
   2400    run-time bounds-checking of accesses in a checked build.  */
   2401 
   2402 class source_line
   2403 {
   2404 public:
   2405   source_line (const char *filename, int line);
   2406 
   2407   char_span as_span () { return char_span (chars, width); }
   2408 
   2409   const char *chars;
   2410   int width;
   2411 };
   2412 
   2413 /* source_line's ctor.  */
   2414 
   2415 source_line::source_line (const char *filename, int line)
   2416 {
   2417   char_span span = location_get_source_line (filename, line);
   2418   chars = span.get_buffer ();
   2419   width = span.length ();
   2420 }
   2421 
   2422 /* Add HINT to the corrections for this line.
   2423    Attempt to consolidate nearby hints so that they will not
   2424    overlap with printed.  */
   2425 
   2426 void
   2427 line_corrections::add_hint (const fixit_hint *hint)
   2428 {
   2429   column_range affected_bytes = get_affected_range (m_policy, hint, CU_BYTES);
   2430   column_range affected_columns = get_affected_range (m_policy, hint,
   2431 						      CU_DISPLAY_COLS);
   2432   column_range printed_columns = get_printed_columns (m_policy, hint);
   2433 
   2434   /* Potentially consolidate.  */
   2435   if (!m_corrections.is_empty ())
   2436     {
   2437       correction *last_correction
   2438 	= m_corrections[m_corrections.length () - 1];
   2439 
   2440       /* The following consolidation code assumes that the fix-it hints
   2441 	 have been sorted by start (done within layout's ctor).  */
   2442       gcc_assert (affected_bytes.start
   2443 		  >= last_correction->m_affected_bytes.start);
   2444       gcc_assert (printed_columns.start
   2445 		  >= last_correction->m_printed_columns.start);
   2446 
   2447       if (printed_columns.start <= last_correction->m_printed_columns.finish)
   2448 	{
   2449 	  /* We have two hints for which the printed forms of the hints
   2450 	     would touch or overlap, so we need to consolidate them to avoid
   2451 	     confusing the user.
   2452 	     Attempt to inject a "replace" correction from immediately
   2453 	     after the end of the last hint to immediately before the start
   2454 	     of the next hint.  */
   2455 	  column_range between (last_correction->m_affected_bytes.finish + 1,
   2456 				affected_bytes.start - 1);
   2457 
   2458 	  /* Try to read the source.  */
   2459 	  source_line line (m_filename, m_row);
   2460 	  if (line.chars && between.finish < line.width)
   2461 	    {
   2462 	      /* Consolidate into the last correction:
   2463 		 add a no-op "replace" of the "between" text, and
   2464 		 add the text from the new hint.  */
   2465 	      int old_byte_len = last_correction->m_byte_length;
   2466 	      gcc_assert (old_byte_len >= 0);
   2467 	      int between_byte_len = between.finish + 1 - between.start;
   2468 	      gcc_assert (between_byte_len >= 0);
   2469 	      int new_byte_len
   2470 		= old_byte_len + between_byte_len + hint->get_length ();
   2471 	      gcc_assert (new_byte_len >= 0);
   2472 	      last_correction->ensure_capacity (new_byte_len);
   2473 	      last_correction->overwrite
   2474 		(old_byte_len,
   2475 		 line.as_span ().subspan (between.start - 1,
   2476 					  between.finish + 1 - between.start));
   2477 	      last_correction->overwrite (old_byte_len + between_byte_len,
   2478 					  char_span (hint->get_string (),
   2479 						     hint->get_length ()));
   2480 	      last_correction->m_byte_length = new_byte_len;
   2481 	      last_correction->ensure_terminated ();
   2482 	      last_correction->m_affected_bytes.finish
   2483 		= affected_bytes.finish;
   2484 	      last_correction->m_affected_columns.finish
   2485 		= affected_columns.finish;
   2486 	      int prev_display_cols = last_correction->m_display_cols;
   2487 	      last_correction->compute_display_cols ();
   2488 	      last_correction->m_printed_columns.finish
   2489 		+= last_correction->m_display_cols - prev_display_cols;
   2490 	      return;
   2491 	    }
   2492 	}
   2493     }
   2494 
   2495   /* If no consolidation happened, add a new correction instance.  */
   2496   m_corrections.safe_push (new correction (affected_bytes,
   2497 					   affected_columns,
   2498 					   printed_columns,
   2499 					   hint->get_string (),
   2500 					   hint->get_length (),
   2501 					   m_policy));
   2502 }
   2503 
   2504 /* If there are any fixit hints on source line ROW, print them.
   2505    They are printed in order, attempting to combine them onto lines, but
   2506    starting new lines if necessary.
   2507    Fix-it hints that insert new lines are handled separately,
   2508    in layout::print_leading_fixits.  */
   2509 
   2510 void
   2511 layout::print_trailing_fixits (linenum_type row)
   2512 {
   2513   /* Build a list of correction instances for the line,
   2514      potentially consolidating hints (for the sake of readability).  */
   2515   line_corrections corrections (m_policy, m_exploc.file, row);
   2516   for (unsigned int i = 0; i < m_fixit_hints.length (); i++)
   2517     {
   2518       const fixit_hint *hint = m_fixit_hints[i];
   2519 
   2520       /* Newline fixits are handled by layout::print_leading_fixits.  */
   2521       if (hint->ends_with_newline_p ())
   2522 	continue;
   2523 
   2524       if (hint->affects_line_p (m_exploc.file, row))
   2525 	corrections.add_hint (hint);
   2526     }
   2527 
   2528   /* Now print the corrections.  */
   2529   unsigned i;
   2530   correction *c;
   2531   int column = m_x_offset_display;
   2532 
   2533   if (!corrections.m_corrections.is_empty ())
   2534     start_annotation_line ();
   2535 
   2536   FOR_EACH_VEC_ELT (corrections.m_corrections, i, c)
   2537     {
   2538       /* For now we assume each fixit hint can only touch one line.  */
   2539       if (c->insertion_p ())
   2540 	{
   2541 	  /* This assumes the insertion just affects one line.  */
   2542 	  int start_column = c->m_printed_columns.start;
   2543 	  move_to_column (&column, start_column, true);
   2544 	  m_colorizer.set_fixit_insert ();
   2545 	  pp_string (m_pp, c->m_text);
   2546 	  m_colorizer.set_normal_text ();
   2547 	  column += c->m_display_cols;
   2548 	}
   2549       else
   2550 	{
   2551 	  /* If the range of the replacement wasn't printed in the
   2552 	     annotation line, then print an extra underline to
   2553 	     indicate exactly what is being replaced.
   2554 	     Always show it for removals.  */
   2555 	  int start_column = c->m_affected_columns.start;
   2556 	  int finish_column = c->m_affected_columns.finish;
   2557 	  if (!annotation_line_showed_range_p (row, start_column,
   2558 					       finish_column)
   2559 	      || c->m_byte_length == 0)
   2560 	    {
   2561 	      move_to_column (&column, start_column, true);
   2562 	      m_colorizer.set_fixit_delete ();
   2563 	      for (; column <= finish_column; column++)
   2564 		pp_character (m_pp, '-');
   2565 	      m_colorizer.set_normal_text ();
   2566 	    }
   2567 	  /* Print the replacement text.  REPLACE also covers
   2568 	     removals, so only do this extra work (potentially starting
   2569 	     a new line) if we have actual replacement text.  */
   2570 	  if (c->m_byte_length > 0)
   2571 	    {
   2572 	      move_to_column (&column, start_column, true);
   2573 	      m_colorizer.set_fixit_insert ();
   2574 	      pp_string (m_pp, c->m_text);
   2575 	      m_colorizer.set_normal_text ();
   2576 	      column += c->m_display_cols;
   2577 	    }
   2578 	}
   2579     }
   2580 
   2581   /* Add a trailing newline, if necessary.  */
   2582   move_to_column (&column, 0, false);
   2583 }
   2584 
   2585 /* Disable any colorization and emit a newline.  */
   2586 
   2587 void
   2588 layout::print_newline ()
   2589 {
   2590   m_colorizer.set_normal_text ();
   2591   pp_newline (m_pp);
   2592 }
   2593 
   2594 /* Return true if (ROW/COLUMN) is within a range of the layout.
   2595    If it returns true, OUT_STATE is written to, with the
   2596    range index, and whether we should draw the caret at
   2597    (ROW/COLUMN) (as opposed to an underline).  COL_UNIT controls
   2598    whether all inputs and outputs are in bytes or display column units.  */
   2599 
   2600 bool
   2601 layout::get_state_at_point (/* Inputs.  */
   2602 			    linenum_type row, int column,
   2603 			    int first_non_ws, int last_non_ws,
   2604 			    enum column_unit col_unit,
   2605 			    /* Outputs.  */
   2606 			    point_state *out_state)
   2607 {
   2608   layout_range *range;
   2609   int i;
   2610   FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
   2611     {
   2612       if (range->m_range_display_kind == SHOW_LINES_WITHOUT_RANGE)
   2613 	/* Bail out early, so that such ranges don't affect underlining or
   2614 	   source colorization.  */
   2615 	continue;
   2616 
   2617       if (range->contains_point (row, column, col_unit))
   2618 	{
   2619 	  out_state->range_idx = i;
   2620 
   2621 	  /* Are we at the range's caret?  is it visible? */
   2622 	  out_state->draw_caret_p = false;
   2623 	  if (range->m_range_display_kind == SHOW_RANGE_WITH_CARET
   2624 	      && row == range->m_caret.m_line
   2625 	      && column == range->m_caret.m_columns[col_unit])
   2626 	    out_state->draw_caret_p = true;
   2627 
   2628 	  /* Within a multiline range, don't display any underline
   2629 	     in any leading or trailing whitespace on a line.
   2630 	     We do display carets, however.  */
   2631 	  if (!out_state->draw_caret_p)
   2632 	    if (column < first_non_ws || column > last_non_ws)
   2633 	      return false;
   2634 
   2635 	  /* We are within a range.  */
   2636 	  return true;
   2637 	}
   2638     }
   2639 
   2640   return false;
   2641 }
   2642 
   2643 /* Helper function for use by layout::print_line when printing the
   2644    annotation line under the source line.
   2645    Get the display column beyond the rightmost one that could contain a caret
   2646    or range marker, given that we stop rendering at trailing whitespace.
   2647    ROW is the source line within the given file.
   2648    CARET_COLUMN is the display column of range 0's caret.
   2649    LAST_NON_WS_COLUMN is the last display column containing a non-whitespace
   2650    character of source (as determined when printing the source line).  */
   2651 
   2652 int
   2653 layout::get_x_bound_for_row (linenum_type row, int caret_column,
   2654 			     int last_non_ws_column)
   2655 {
   2656   int result = caret_column + 1;
   2657 
   2658   layout_range *range;
   2659   int i;
   2660   FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
   2661     {
   2662       if (row >= range->m_start.m_line)
   2663 	{
   2664 	  if (range->m_finish.m_line == row)
   2665 	    {
   2666 	      /* On the final line within a range; ensure that
   2667 		 we render up to the end of the range.  */
   2668 	      const int disp_col = range->m_finish.m_columns[CU_DISPLAY_COLS];
   2669 	      if (result <= disp_col)
   2670 		result = disp_col + 1;
   2671 	    }
   2672 	  else if (row < range->m_finish.m_line)
   2673 	    {
   2674 	      /* Within a multiline range; ensure that we render up to the
   2675 		 last non-whitespace column.  */
   2676 	      if (result <= last_non_ws_column)
   2677 		result = last_non_ws_column + 1;
   2678 	    }
   2679 	}
   2680     }
   2681 
   2682   return result;
   2683 }
   2684 
   2685 /* Given *COLUMN as an x-coordinate, print spaces to position
   2686    successive output at DEST_COLUMN, printing a newline if necessary,
   2687    and updating *COLUMN.  If ADD_LEFT_MARGIN, then print the (empty)
   2688    left margin after any newline.  */
   2689 
   2690 void
   2691 layout::move_to_column (int *column, int dest_column, bool add_left_margin)
   2692 {
   2693   /* Start a new line if we need to.  */
   2694   if (*column > dest_column)
   2695     {
   2696       print_newline ();
   2697       if (add_left_margin)
   2698 	start_annotation_line ();
   2699       *column = m_x_offset_display;
   2700     }
   2701 
   2702   while (*column < dest_column)
   2703     {
   2704       pp_space (m_pp);
   2705       (*column)++;
   2706     }
   2707 }
   2708 
   2709 /* For debugging layout issues, render a ruler giving column numbers
   2710    (after the 1-column indent).  */
   2711 
   2712 void
   2713 layout::show_ruler (int max_column) const
   2714 {
   2715   /* Hundreds.  */
   2716   if (max_column > 99)
   2717     {
   2718       start_annotation_line ();
   2719       pp_space (m_pp);
   2720       for (int column = 1 + m_x_offset_display; column <= max_column; column++)
   2721 	if (column % 10 == 0)
   2722 	  pp_character (m_pp, '0' + (column / 100) % 10);
   2723 	else
   2724 	  pp_space (m_pp);
   2725       pp_newline (m_pp);
   2726     }
   2727 
   2728   /* Tens.  */
   2729   start_annotation_line ();
   2730   pp_space (m_pp);
   2731   for (int column = 1 + m_x_offset_display; column <= max_column; column++)
   2732     if (column % 10 == 0)
   2733       pp_character (m_pp, '0' + (column / 10) % 10);
   2734     else
   2735       pp_space (m_pp);
   2736   pp_newline (m_pp);
   2737 
   2738   /* Units.  */
   2739   start_annotation_line ();
   2740   pp_space (m_pp);
   2741   for (int column = 1 + m_x_offset_display; column <= max_column; column++)
   2742     pp_character (m_pp, '0' + (column % 10));
   2743   pp_newline (m_pp);
   2744 }
   2745 
   2746 /* Print leading fix-its (for new lines inserted before the source line)
   2747    then the source line, followed by an annotation line
   2748    consisting of any caret/underlines, then any fixits.
   2749    If the source line can't be read, print nothing.  */
   2750 void
   2751 layout::print_line (linenum_type row)
   2752 {
   2753   char_span line = location_get_source_line (m_exploc.file, row);
   2754   if (!line)
   2755     return;
   2756 
   2757   print_leading_fixits (row);
   2758   const line_bounds lbounds
   2759     = print_source_line (row, line.get_buffer (), line.length ());
   2760   if (should_print_annotation_line_p (row))
   2761     print_annotation_line (row, lbounds);
   2762   if (m_show_labels_p)
   2763     print_any_labels (row);
   2764   print_trailing_fixits (row);
   2765 }
   2766 
   2767 } /* End of anonymous namespace.  */
   2768 
   2769 /* If LOC is within the spans of lines that will already be printed for
   2770    this gcc_rich_location, then add it as a secondary location and return true.
   2771 
   2772    Otherwise return false.  */
   2773 
   2774 bool
   2775 gcc_rich_location::add_location_if_nearby (location_t loc,
   2776 					   bool restrict_to_current_line_spans,
   2777 					   const range_label *label)
   2778 {
   2779   /* Use the layout location-handling logic to sanitize LOC,
   2780      filtering it to the current line spans within a temporary
   2781      layout instance.  */
   2782   layout layout (global_dc, this, DK_ERROR);
   2783   location_range loc_range;
   2784   loc_range.m_loc = loc;
   2785   loc_range.m_range_display_kind = SHOW_RANGE_WITHOUT_CARET;
   2786   if (!layout.maybe_add_location_range (&loc_range, 0,
   2787 					restrict_to_current_line_spans))
   2788     return false;
   2789 
   2790   add_range (loc, SHOW_RANGE_WITHOUT_CARET, label);
   2791   return true;
   2792 }
   2793 
   2794 /* Print the physical source code corresponding to the location of
   2795    this diagnostic, with additional annotations.  */
   2796 
   2797 void
   2798 diagnostic_show_locus (diagnostic_context * context,
   2799 		       rich_location *richloc,
   2800 		       diagnostic_t diagnostic_kind)
   2801 {
   2802   location_t loc = richloc->get_loc ();
   2803   /* Do nothing if source-printing has been disabled.  */
   2804   if (!context->show_caret)
   2805     return;
   2806 
   2807   /* Don't attempt to print source for UNKNOWN_LOCATION and for builtins.  */
   2808   if (loc <= BUILTINS_LOCATION)
   2809     return;
   2810 
   2811   /* Don't print the same source location twice in a row, unless we have
   2812      fix-it hints, or multiple locations, or a label.  */
   2813   if (loc == context->last_location
   2814       && richloc->get_num_fixit_hints () == 0
   2815       && richloc->get_num_locations () == 1
   2816       && richloc->get_range (0)->m_label == NULL)
   2817     return;
   2818 
   2819   context->last_location = loc;
   2820 
   2821   layout layout (context, richloc, diagnostic_kind);
   2822   for (int line_span_idx = 0; line_span_idx < layout.get_num_line_spans ();
   2823        line_span_idx++)
   2824     {
   2825       const line_span *line_span = layout.get_line_span (line_span_idx);
   2826       if (context->show_line_numbers_p)
   2827 	{
   2828 	  /* With line numbers, we should show whenever the line-numbering
   2829 	     "jumps".  */
   2830 	  if (line_span_idx > 0)
   2831 	    layout.print_gap_in_line_numbering ();
   2832 	}
   2833       else
   2834 	{
   2835 	  /* Without line numbers, we print headings for some line spans.  */
   2836 	  if (layout.print_heading_for_line_span_index_p (line_span_idx))
   2837 	    {
   2838 	      expanded_location exploc
   2839 		= layout.get_expanded_location (line_span);
   2840 	      context->start_span (context, exploc);
   2841 	    }
   2842 	}
   2843       /* Iterate over the lines within this span (using linenum_arith_t to
   2844 	 avoid overflow with 0xffffffff causing an infinite loop).  */
   2845       linenum_arith_t last_line = line_span->get_last_line ();
   2846       for (linenum_arith_t row = line_span->get_first_line ();
   2847 	   row <= last_line; row++)
   2848 	layout.print_line (row);
   2849     }
   2850 }
   2851 
   2852 #if CHECKING_P
   2853 
   2854 namespace selftest {
   2855 
   2856 /* Selftests for diagnostic_show_locus.  */
   2857 
   2858 /* Verify that cpp_display_width correctly handles escaping.  */
   2859 
   2860 static void
   2861 test_display_widths ()
   2862 {
   2863   gcc_rich_location richloc (UNKNOWN_LOCATION);
   2864 
   2865   /* U+03C0 "GREEK SMALL LETTER PI".  */
   2866   const char *pi = "\xCF\x80";
   2867   /* U+1F642 "SLIGHTLY SMILING FACE".  */
   2868   const char *emoji = "\xF0\x9F\x99\x82";
   2869   /* Stray trailing byte of a UTF-8 character.  */
   2870   const char *stray = "\xBF";
   2871   /* U+10FFFF.  */
   2872   const char *max_codepoint = "\xF4\x8F\xBF\xBF";
   2873 
   2874   /* No escaping.  */
   2875   {
   2876     test_diagnostic_context dc;
   2877     char_display_policy policy (make_policy (dc, richloc));
   2878     ASSERT_EQ (cpp_display_width (pi, strlen (pi), policy), 1);
   2879     ASSERT_EQ (cpp_display_width (emoji, strlen (emoji), policy), 2);
   2880     ASSERT_EQ (cpp_display_width (stray, strlen (stray), policy), 1);
   2881     /* Don't check width of U+10FFFF; it's in a private use plane.  */
   2882   }
   2883 
   2884   richloc.set_escape_on_output (true);
   2885 
   2886   {
   2887     test_diagnostic_context dc;
   2888     dc.escape_format = DIAGNOSTICS_ESCAPE_FORMAT_UNICODE;
   2889     char_display_policy policy (make_policy (dc, richloc));
   2890     ASSERT_EQ (cpp_display_width (pi, strlen (pi), policy), 8);
   2891     ASSERT_EQ (cpp_display_width (emoji, strlen (emoji), policy), 9);
   2892     ASSERT_EQ (cpp_display_width (stray, strlen (stray), policy), 4);
   2893     ASSERT_EQ (cpp_display_width (max_codepoint, strlen (max_codepoint),
   2894 				  policy),
   2895 	       strlen ("<U+10FFFF>"));
   2896   }
   2897 
   2898   {
   2899     test_diagnostic_context dc;
   2900     dc.escape_format = DIAGNOSTICS_ESCAPE_FORMAT_BYTES;
   2901     char_display_policy policy (make_policy (dc, richloc));
   2902     ASSERT_EQ (cpp_display_width (pi, strlen (pi), policy), 8);
   2903     ASSERT_EQ (cpp_display_width (emoji, strlen (emoji), policy), 16);
   2904     ASSERT_EQ (cpp_display_width (stray, strlen (stray), policy), 4);
   2905     ASSERT_EQ (cpp_display_width (max_codepoint, strlen (max_codepoint),
   2906 				  policy),
   2907 	       16);
   2908   }
   2909 }
   2910 
   2911 /* For precise tests of the layout, make clear where the source line will
   2912    start.  test_left_margin sets the total byte count from the left side of the
   2913    screen to the start of source lines, after the line number and the separator,
   2914    which consists of the three characters " | ".  */
   2915 static const int test_linenum_sep = 3;
   2916 static const int test_left_margin = 7;
   2917 
   2918 /* Helper function for test_layout_x_offset_display_utf8().  */
   2919 static void
   2920 test_offset_impl (int caret_byte_col, int max_width,
   2921 		  int expected_x_offset_display,
   2922 		  int left_margin = test_left_margin)
   2923 {
   2924   test_diagnostic_context dc;
   2925   dc.caret_max_width = max_width;
   2926   /* diagnostic_context::min_margin_width sets the minimum space reserved for
   2927      the line number plus one space after.  */
   2928   dc.min_margin_width = left_margin - test_linenum_sep + 1;
   2929   dc.show_line_numbers_p = true;
   2930   rich_location richloc (line_table,
   2931 			 linemap_position_for_column (line_table,
   2932 						      caret_byte_col));
   2933   layout test_layout (&dc, &richloc, DK_ERROR);
   2934   ASSERT_EQ (left_margin - test_linenum_sep,
   2935 	     test_layout.get_linenum_width ());
   2936   ASSERT_EQ (expected_x_offset_display,
   2937 	     test_layout.get_x_offset_display ());
   2938 }
   2939 
   2940 /* Test that layout::calculate_x_offset_display() works.  */
   2941 static void
   2942 test_layout_x_offset_display_utf8 (const line_table_case &case_)
   2943 {
   2944 
   2945   const char *content
   2946     = "This line is very long, so that we can use it to test the logic for "
   2947       "clipping long lines.  Also this: \xf0\x9f\x98\x82\xf0\x9f\x98\x82 is a "
   2948       "pair of emojis that occupies 8 bytes and 4 display columns, starting at "
   2949       "column #102.\n";
   2950 
   2951   /* Number of bytes in the line, subtracting one to remove the newline.  */
   2952   const int line_bytes = strlen (content) - 1;
   2953 
   2954   /* Number of display columns occupied by the line; each of the 2 emojis
   2955      takes up 2 fewer display columns than it does bytes.  */
   2956   const int line_display_cols = line_bytes - 2*2;
   2957 
   2958   /* The column of the first emoji.  Byte or display is the same as there are
   2959      no multibyte characters earlier on the line.  */
   2960   const int emoji_col = 102;
   2961 
   2962   temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
   2963   line_table_test ltt (case_);
   2964 
   2965   linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
   2966 
   2967   location_t line_end = linemap_position_for_column (line_table, line_bytes);
   2968 
   2969   /* Don't attempt to run the tests if column data might be unavailable.  */
   2970   if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
   2971     return;
   2972 
   2973   ASSERT_STREQ (tmp.get_filename (), LOCATION_FILE (line_end));
   2974   ASSERT_EQ (1, LOCATION_LINE (line_end));
   2975   ASSERT_EQ (line_bytes, LOCATION_COLUMN (line_end));
   2976 
   2977   char_span lspan = location_get_source_line (tmp.get_filename (), 1);
   2978   ASSERT_EQ (line_display_cols,
   2979 	     cpp_display_width (lspan.get_buffer (), lspan.length (),
   2980 				def_policy ()));
   2981   ASSERT_EQ (line_display_cols,
   2982 	     location_compute_display_column (expand_location (line_end),
   2983 					      def_policy ()));
   2984   ASSERT_EQ (0, memcmp (lspan.get_buffer () + (emoji_col - 1),
   2985 			"\xf0\x9f\x98\x82\xf0\x9f\x98\x82", 8));
   2986 
   2987   /* (caret_byte, max_width, expected_x_offset_display, [left_margin])  */
   2988 
   2989   /* No constraint on the width -> no offset.  */
   2990   test_offset_impl (emoji_col, 0, 0);
   2991 
   2992   /* Caret is before the beginning -> no offset.  */
   2993   test_offset_impl (0, 100, 0);
   2994 
   2995   /* Caret is past the end of the line -> no offset.  */
   2996   test_offset_impl (line_bytes+1, 100, 0);
   2997 
   2998   /* Line fits in the display -> no offset.  */
   2999   test_offset_impl (line_bytes, line_display_cols + test_left_margin, 0);
   3000   test_offset_impl (emoji_col, line_display_cols + test_left_margin, 0);
   3001 
   3002   /* Line is too long for the display but caret location is OK
   3003      anyway -> no offset.  */
   3004   static const int small_width = 24;
   3005   test_offset_impl (1, small_width, 0);
   3006 
   3007   /* Width constraint is very small -> no offset.  */
   3008   test_offset_impl (emoji_col, CARET_LINE_MARGIN, 0);
   3009 
   3010   /* Line would be offset, but due to large line numbers, offsetting
   3011      would remove the whole line -> no offset.  */
   3012   static const int huge_left_margin = 100;
   3013   test_offset_impl (emoji_col, huge_left_margin, 0, huge_left_margin);
   3014 
   3015   /* Line is the same length as the display, but the line number makes it too
   3016      long, so offset is required.  Caret is at the end so padding on the right
   3017      is not in effect.  */
   3018   for (int excess = 1; excess <= 3; ++excess)
   3019     test_offset_impl (line_bytes, line_display_cols + test_left_margin - excess,
   3020 		      excess);
   3021 
   3022   /* Line is much too long for the display, caret is near the end ->
   3023      offset should be such that the line fits in the display and caret
   3024      remains the same distance from the end that it was.  */
   3025   for (int caret_offset = 0, max_offset = MIN (CARET_LINE_MARGIN, 10);
   3026        caret_offset <= max_offset; ++caret_offset)
   3027     test_offset_impl (line_bytes - caret_offset, small_width,
   3028 		      line_display_cols + test_left_margin - small_width);
   3029 
   3030   /* As previous case but caret is closer to the middle; now we want it to end
   3031      up CARET_LINE_MARGIN bytes from the end.  */
   3032   ASSERT_GT (line_display_cols - emoji_col, CARET_LINE_MARGIN);
   3033   test_offset_impl (emoji_col, small_width,
   3034 		    emoji_col + test_left_margin
   3035 		    - (small_width - CARET_LINE_MARGIN));
   3036 
   3037   /* Test that the source line is offset as expected when printed.  */
   3038   {
   3039     test_diagnostic_context dc;
   3040     dc.caret_max_width = small_width - 6;
   3041     dc.min_margin_width = test_left_margin - test_linenum_sep + 1;
   3042     dc.show_line_numbers_p = true;
   3043     dc.show_ruler_p = true;
   3044     rich_location richloc (line_table,
   3045 			   linemap_position_for_column (line_table,
   3046 							emoji_col));
   3047     layout test_layout (&dc, &richloc, DK_ERROR);
   3048     test_layout.print_line (1);
   3049     ASSERT_STREQ ("     |         1         \n"
   3050 		  "     |         1         \n"
   3051 		  "     | 234567890123456789\n"
   3052 		  "   1 | \xf0\x9f\x98\x82\xf0\x9f\x98\x82 is a pair of emojis "
   3053 		  "that occupies 8 bytes and 4 display columns, starting at "
   3054 		  "column #102.\n"
   3055 		  "     | ^\n\n",
   3056 		  pp_formatted_text (dc.printer));
   3057   }
   3058 
   3059   /* Similar to the previous example, but now the offset called for would split
   3060      the first emoji in the middle of the UTF-8 sequence.  Check that we replace
   3061      it with a padding space in this case.  */
   3062   {
   3063     test_diagnostic_context dc;
   3064     dc.caret_max_width = small_width - 5;
   3065     dc.min_margin_width = test_left_margin - test_linenum_sep + 1;
   3066     dc.show_line_numbers_p = true;
   3067     dc.show_ruler_p = true;
   3068     rich_location richloc (line_table,
   3069 			   linemap_position_for_column (line_table,
   3070 							emoji_col + 2));
   3071     layout test_layout (&dc, &richloc, DK_ERROR);
   3072     test_layout.print_line (1);
   3073     ASSERT_STREQ ("     |        1         1 \n"
   3074 		  "     |        1         2 \n"
   3075 		  "     | 3456789012345678901\n"
   3076 		  "   1 |  \xf0\x9f\x98\x82 is a pair of emojis "
   3077 		  "that occupies 8 bytes and 4 display columns, starting at "
   3078 		  "column #102.\n"
   3079 		  "     |  ^\n\n",
   3080 		  pp_formatted_text (dc.printer));
   3081   }
   3082 
   3083 }
   3084 
   3085 static void
   3086 test_layout_x_offset_display_tab (const line_table_case &case_)
   3087 {
   3088   const char *content
   3089     = "This line is very long, so that we can use it to test the logic for "
   3090       "clipping long lines.  Also this: `\t' is a tab that occupies 1 byte and "
   3091       "a variable number of display columns, starting at column #103.\n";
   3092 
   3093   /* Number of bytes in the line, subtracting one to remove the newline.  */
   3094   const int line_bytes = strlen (content) - 1;
   3095 
   3096  /* The column where the tab begins.  Byte or display is the same as there are
   3097     no multibyte characters earlier on the line.  */
   3098   const int tab_col = 103;
   3099 
   3100   /* Effective extra size of the tab beyond what a single space would have taken
   3101      up, indexed by tabstop.  */
   3102   static const int num_tabstops = 11;
   3103   int extra_width[num_tabstops];
   3104   for (int tabstop = 1; tabstop != num_tabstops; ++tabstop)
   3105     {
   3106       const int this_tab_size = tabstop - (tab_col - 1) % tabstop;
   3107       extra_width[tabstop] = this_tab_size - 1;
   3108     }
   3109   /* Example of this calculation: if tabstop is 10, the tab starting at column
   3110      #103 has to expand into 8 spaces, covering columns 103-110, so that the
   3111      next character is at column #111.  So it takes up 7 more columns than
   3112      a space would have taken up.  */
   3113   ASSERT_EQ (7, extra_width[10]);
   3114 
   3115   temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
   3116   line_table_test ltt (case_);
   3117 
   3118   linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
   3119 
   3120   location_t line_end = linemap_position_for_column (line_table, line_bytes);
   3121 
   3122   /* Don't attempt to run the tests if column data might be unavailable.  */
   3123   if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
   3124     return;
   3125 
   3126   /* Check that cpp_display_width handles the tabs as expected.  */
   3127   char_span lspan = location_get_source_line (tmp.get_filename (), 1);
   3128   ASSERT_EQ ('\t', *(lspan.get_buffer () + (tab_col - 1)));
   3129   for (int tabstop = 1; tabstop != num_tabstops; ++tabstop)
   3130     {
   3131       cpp_char_column_policy policy (tabstop, cpp_wcwidth);
   3132       ASSERT_EQ (line_bytes + extra_width[tabstop],
   3133 		 cpp_display_width (lspan.get_buffer (), lspan.length (),
   3134 				    policy));
   3135       ASSERT_EQ (line_bytes + extra_width[tabstop],
   3136 		 location_compute_display_column (expand_location (line_end),
   3137 						  policy));
   3138     }
   3139 
   3140   /* Check that the tab is expanded to the expected number of spaces.  */
   3141   rich_location richloc (line_table,
   3142 			 linemap_position_for_column (line_table,
   3143 						      tab_col + 1));
   3144   for (int tabstop = 1; tabstop != num_tabstops; ++tabstop)
   3145     {
   3146       test_diagnostic_context dc;
   3147       dc.tabstop = tabstop;
   3148       layout test_layout (&dc, &richloc, DK_ERROR);
   3149       test_layout.print_line (1);
   3150       const char *out = pp_formatted_text (dc.printer);
   3151       ASSERT_EQ (NULL, strchr (out, '\t'));
   3152       const char *left_quote = strchr (out, '`');
   3153       const char *right_quote = strchr (out, '\'');
   3154       ASSERT_NE (NULL, left_quote);
   3155       ASSERT_NE (NULL, right_quote);
   3156       ASSERT_EQ (right_quote - left_quote, extra_width[tabstop] + 2);
   3157     }
   3158 
   3159   /* Check that the line is offset properly and that the tab is broken up
   3160      into the expected number of spaces when it is the last character skipped
   3161      over.  */
   3162   for (int tabstop = 1; tabstop != num_tabstops; ++tabstop)
   3163     {
   3164       test_diagnostic_context dc;
   3165       dc.tabstop = tabstop;
   3166       static const int small_width = 24;
   3167       dc.caret_max_width = small_width - 4;
   3168       dc.min_margin_width = test_left_margin - test_linenum_sep + 1;
   3169       dc.show_line_numbers_p = true;
   3170       layout test_layout (&dc, &richloc, DK_ERROR);
   3171       test_layout.print_line (1);
   3172 
   3173       /* We have arranged things so that two columns will be printed before
   3174 	 the caret.  If the tab results in more than one space, this should
   3175 	 produce two spaces in the output; otherwise, it will be a single space
   3176 	 preceded by the opening quote before the tab character.  */
   3177       const char *output1
   3178 	= "   1 |   ' is a tab that occupies 1 byte and a variable number of "
   3179 	  "display columns, starting at column #103.\n"
   3180 	  "     |   ^\n\n";
   3181       const char *output2
   3182 	= "   1 | ` ' is a tab that occupies 1 byte and a variable number of "
   3183 	  "display columns, starting at column #103.\n"
   3184 	  "     |   ^\n\n";
   3185       const char *expected_output = (extra_width[tabstop] ? output1 : output2);
   3186       ASSERT_STREQ (expected_output, pp_formatted_text (dc.printer));
   3187     }
   3188 }
   3189 
   3190 
   3191 /* Verify that diagnostic_show_locus works sanely on UNKNOWN_LOCATION.  */
   3192 
   3193 static void
   3194 test_diagnostic_show_locus_unknown_location ()
   3195 {
   3196   test_diagnostic_context dc;
   3197   rich_location richloc (line_table, UNKNOWN_LOCATION);
   3198   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3199   ASSERT_STREQ ("", pp_formatted_text (dc.printer));
   3200 }
   3201 
   3202 /* Verify that diagnostic_show_locus works sanely for various
   3203    single-line cases.
   3204 
   3205    All of these work on the following 1-line source file:
   3206      .0000000001111111
   3207      .1234567890123456
   3208      "foo = bar.field;\n"
   3209    which is set up by test_diagnostic_show_locus_one_liner and calls
   3210    them.  */
   3211 
   3212 /* Just a caret.  */
   3213 
   3214 static void
   3215 test_one_liner_simple_caret ()
   3216 {
   3217   test_diagnostic_context dc;
   3218   location_t caret = linemap_position_for_column (line_table, 10);
   3219   rich_location richloc (line_table, caret);
   3220   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3221   ASSERT_STREQ (" foo = bar.field;\n"
   3222 		"          ^\n",
   3223 		pp_formatted_text (dc.printer));
   3224 }
   3225 
   3226 /* Caret and range.  */
   3227 
   3228 static void
   3229 test_one_liner_caret_and_range ()
   3230 {
   3231   test_diagnostic_context dc;
   3232   location_t caret = linemap_position_for_column (line_table, 10);
   3233   location_t start = linemap_position_for_column (line_table, 7);
   3234   location_t finish = linemap_position_for_column (line_table, 15);
   3235   location_t loc = make_location (caret, start, finish);
   3236   rich_location richloc (line_table, loc);
   3237   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3238   ASSERT_STREQ (" foo = bar.field;\n"
   3239 		"       ~~~^~~~~~\n",
   3240 		pp_formatted_text (dc.printer));
   3241 }
   3242 
   3243 /* Multiple ranges and carets.  */
   3244 
   3245 static void
   3246 test_one_liner_multiple_carets_and_ranges ()
   3247 {
   3248   test_diagnostic_context dc;
   3249   location_t foo
   3250     = make_location (linemap_position_for_column (line_table, 2),
   3251 		     linemap_position_for_column (line_table, 1),
   3252 		     linemap_position_for_column (line_table, 3));
   3253   dc.caret_chars[0] = 'A';
   3254 
   3255   location_t bar
   3256     = make_location (linemap_position_for_column (line_table, 8),
   3257 		     linemap_position_for_column (line_table, 7),
   3258 		     linemap_position_for_column (line_table, 9));
   3259   dc.caret_chars[1] = 'B';
   3260 
   3261   location_t field
   3262     = make_location (linemap_position_for_column (line_table, 13),
   3263 		     linemap_position_for_column (line_table, 11),
   3264 		     linemap_position_for_column (line_table, 15));
   3265   dc.caret_chars[2] = 'C';
   3266 
   3267   rich_location richloc (line_table, foo);
   3268   richloc.add_range (bar, SHOW_RANGE_WITH_CARET);
   3269   richloc.add_range (field, SHOW_RANGE_WITH_CARET);
   3270   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3271   ASSERT_STREQ (" foo = bar.field;\n"
   3272 		" ~A~   ~B~ ~~C~~\n",
   3273 		pp_formatted_text (dc.printer));
   3274 }
   3275 
   3276 /* Insertion fix-it hint: adding an "&" to the front of "bar.field". */
   3277 
   3278 static void
   3279 test_one_liner_fixit_insert_before ()
   3280 {
   3281   test_diagnostic_context dc;
   3282   location_t caret = linemap_position_for_column (line_table, 7);
   3283   rich_location richloc (line_table, caret);
   3284   richloc.add_fixit_insert_before ("&");
   3285   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3286   ASSERT_STREQ (" foo = bar.field;\n"
   3287 		"       ^\n"
   3288 		"       &\n",
   3289 		pp_formatted_text (dc.printer));
   3290 }
   3291 
   3292 /* Insertion fix-it hint: adding a "[0]" after "foo". */
   3293 
   3294 static void
   3295 test_one_liner_fixit_insert_after ()
   3296 {
   3297   test_diagnostic_context dc;
   3298   location_t start = linemap_position_for_column (line_table, 1);
   3299   location_t finish = linemap_position_for_column (line_table, 3);
   3300   location_t foo = make_location (start, start, finish);
   3301   rich_location richloc (line_table, foo);
   3302   richloc.add_fixit_insert_after ("[0]");
   3303   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3304   ASSERT_STREQ (" foo = bar.field;\n"
   3305 		" ^~~\n"
   3306 		"    [0]\n",
   3307 		pp_formatted_text (dc.printer));
   3308 }
   3309 
   3310 /* Removal fix-it hint: removal of the ".field".
   3311    Also verify the interaction of pp_set_prefix with rulers and
   3312    fix-it hints.  */
   3313 
   3314 static void
   3315 test_one_liner_fixit_remove ()
   3316 {
   3317   location_t start = linemap_position_for_column (line_table, 10);
   3318   location_t finish = linemap_position_for_column (line_table, 15);
   3319   location_t dot = make_location (start, start, finish);
   3320   rich_location richloc (line_table, dot);
   3321   richloc.add_fixit_remove ();
   3322 
   3323   /* Normal.  */
   3324   {
   3325     test_diagnostic_context dc;
   3326     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3327     ASSERT_STREQ (" foo = bar.field;\n"
   3328 		  "          ^~~~~~\n"
   3329 		  "          ------\n",
   3330 		  pp_formatted_text (dc.printer));
   3331   }
   3332 
   3333   /* Test of adding a prefix.  */
   3334   {
   3335     test_diagnostic_context dc;
   3336     pp_prefixing_rule (dc.printer) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
   3337     pp_set_prefix (dc.printer, xstrdup ("TEST PREFIX:"));
   3338     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3339     ASSERT_STREQ ("TEST PREFIX: foo = bar.field;\n"
   3340 		  "TEST PREFIX:          ^~~~~~\n"
   3341 		  "TEST PREFIX:          ------\n",
   3342 		  pp_formatted_text (dc.printer));
   3343   }
   3344 
   3345   /* Normal, with ruler.  */
   3346   {
   3347     test_diagnostic_context dc;
   3348     dc.show_ruler_p = true;
   3349     dc.caret_max_width = 104;
   3350     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3351     ASSERT_STREQ ("          0         0         0         0         0         0         0         0         0         1    \n"
   3352 		  "          1         2         3         4         5         6         7         8         9         0    \n"
   3353 		  " 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234\n"
   3354 		  " foo = bar.field;\n"
   3355 		  "          ^~~~~~\n"
   3356 		  "          ------\n",
   3357 		  pp_formatted_text (dc.printer));
   3358   }
   3359 
   3360   /* Test of adding a prefix, with ruler.  */
   3361   {
   3362     test_diagnostic_context dc;
   3363     dc.show_ruler_p = true;
   3364     dc.caret_max_width = 50;
   3365     pp_prefixing_rule (dc.printer) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
   3366     pp_set_prefix (dc.printer, xstrdup ("TEST PREFIX:"));
   3367     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3368     ASSERT_STREQ ("TEST PREFIX:          1         2         3         4         5\n"
   3369 		  "TEST PREFIX: 12345678901234567890123456789012345678901234567890\n"
   3370 		  "TEST PREFIX: foo = bar.field;\n"
   3371 		  "TEST PREFIX:          ^~~~~~\n"
   3372 		  "TEST PREFIX:          ------\n",
   3373 		  pp_formatted_text (dc.printer));
   3374   }
   3375 
   3376   /* Test of adding a prefix, with ruler and line numbers.  */
   3377   {
   3378     test_diagnostic_context dc;
   3379     dc.show_ruler_p = true;
   3380     dc.caret_max_width = 50;
   3381     dc.show_line_numbers_p = true;
   3382     pp_prefixing_rule (dc.printer) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
   3383     pp_set_prefix (dc.printer, xstrdup ("TEST PREFIX:"));
   3384     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3385     ASSERT_STREQ ("TEST PREFIX:      |          1         2         3         4         5\n"
   3386 		  "TEST PREFIX:      | 12345678901234567890123456789012345678901234567890\n"
   3387 		  "TEST PREFIX:    1 | foo = bar.field;\n"
   3388 		  "TEST PREFIX:      |          ^~~~~~\n"
   3389 		  "TEST PREFIX:      |          ------\n",
   3390 		  pp_formatted_text (dc.printer));
   3391   }
   3392 }
   3393 
   3394 /* Replace fix-it hint: replacing "field" with "m_field". */
   3395 
   3396 static void
   3397 test_one_liner_fixit_replace ()
   3398 {
   3399   test_diagnostic_context dc;
   3400   location_t start = linemap_position_for_column (line_table, 11);
   3401   location_t finish = linemap_position_for_column (line_table, 15);
   3402   location_t field = make_location (start, start, finish);
   3403   rich_location richloc (line_table, field);
   3404   richloc.add_fixit_replace ("m_field");
   3405   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3406   ASSERT_STREQ (" foo = bar.field;\n"
   3407 		"           ^~~~~\n"
   3408 		"           m_field\n",
   3409 		pp_formatted_text (dc.printer));
   3410 }
   3411 
   3412 /* Replace fix-it hint: replacing "field" with "m_field",
   3413    but where the caret was elsewhere.  */
   3414 
   3415 static void
   3416 test_one_liner_fixit_replace_non_equal_range ()
   3417 {
   3418   test_diagnostic_context dc;
   3419   location_t equals = linemap_position_for_column (line_table, 5);
   3420   location_t start = linemap_position_for_column (line_table, 11);
   3421   location_t finish = linemap_position_for_column (line_table, 15);
   3422   rich_location richloc (line_table, equals);
   3423   source_range range;
   3424   range.m_start = start;
   3425   range.m_finish = finish;
   3426   richloc.add_fixit_replace (range, "m_field");
   3427   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3428   /* The replacement range is not indicated in the annotation line, so
   3429      it should be indicated via an additional underline.  */
   3430   ASSERT_STREQ (" foo = bar.field;\n"
   3431 		"     ^\n"
   3432 		"           -----\n"
   3433 		"           m_field\n",
   3434 		pp_formatted_text (dc.printer));
   3435 }
   3436 
   3437 /* Replace fix-it hint: replacing "field" with "m_field",
   3438    where the caret was elsewhere, but where a secondary range
   3439    exactly covers "field".  */
   3440 
   3441 static void
   3442 test_one_liner_fixit_replace_equal_secondary_range ()
   3443 {
   3444   test_diagnostic_context dc;
   3445   location_t equals = linemap_position_for_column (line_table, 5);
   3446   location_t start = linemap_position_for_column (line_table, 11);
   3447   location_t finish = linemap_position_for_column (line_table, 15);
   3448   rich_location richloc (line_table, equals);
   3449   location_t field = make_location (start, start, finish);
   3450   richloc.add_range (field);
   3451   richloc.add_fixit_replace (field, "m_field");
   3452   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3453   /* The replacement range is indicated in the annotation line,
   3454      so it shouldn't be indicated via an additional underline.  */
   3455   ASSERT_STREQ (" foo = bar.field;\n"
   3456 		"     ^     ~~~~~\n"
   3457 		"           m_field\n",
   3458 		pp_formatted_text (dc.printer));
   3459 }
   3460 
   3461 /* Verify that we can use ad-hoc locations when adding fixits to a
   3462    rich_location.  */
   3463 
   3464 static void
   3465 test_one_liner_fixit_validation_adhoc_locations ()
   3466 {
   3467   /* Generate a range that's too long to be packed, so must
   3468      be stored as an ad-hoc location (given the defaults
   3469      of 5 bits or 0 bits of packed range); 41 columns > 2**5.  */
   3470   const location_t c7 = linemap_position_for_column (line_table, 7);
   3471   const location_t c47 = linemap_position_for_column (line_table, 47);
   3472   const location_t loc = make_location (c7, c7, c47);
   3473 
   3474   if (c47 > LINE_MAP_MAX_LOCATION_WITH_COLS)
   3475     return;
   3476 
   3477   ASSERT_TRUE (IS_ADHOC_LOC (loc));
   3478 
   3479   /* Insert.  */
   3480   {
   3481     rich_location richloc (line_table, loc);
   3482     richloc.add_fixit_insert_before (loc, "test");
   3483     /* It should not have been discarded by the validator.  */
   3484     ASSERT_EQ (1, richloc.get_num_fixit_hints ());
   3485 
   3486     test_diagnostic_context dc;
   3487     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3488     ASSERT_STREQ (" foo = bar.field;\n"
   3489 		  "       ^~~~~~~~~~                               \n"
   3490 		  "       test\n",
   3491 		  pp_formatted_text (dc.printer));
   3492   }
   3493 
   3494   /* Remove.  */
   3495   {
   3496     rich_location richloc (line_table, loc);
   3497     source_range range = source_range::from_locations (loc, c47);
   3498     richloc.add_fixit_remove (range);
   3499     /* It should not have been discarded by the validator.  */
   3500     ASSERT_EQ (1, richloc.get_num_fixit_hints ());
   3501 
   3502     test_diagnostic_context dc;
   3503     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3504     ASSERT_STREQ (" foo = bar.field;\n"
   3505 		  "       ^~~~~~~~~~                               \n"
   3506 		  "       -----------------------------------------\n",
   3507 		  pp_formatted_text (dc.printer));
   3508   }
   3509 
   3510   /* Replace.  */
   3511   {
   3512     rich_location richloc (line_table, loc);
   3513     source_range range = source_range::from_locations (loc, c47);
   3514     richloc.add_fixit_replace (range, "test");
   3515     /* It should not have been discarded by the validator.  */
   3516     ASSERT_EQ (1, richloc.get_num_fixit_hints ());
   3517 
   3518     test_diagnostic_context dc;
   3519     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3520     ASSERT_STREQ (" foo = bar.field;\n"
   3521 		  "       ^~~~~~~~~~                               \n"
   3522 		  "       test\n",
   3523 		  pp_formatted_text (dc.printer));
   3524   }
   3525 }
   3526 
   3527 /* Test of consolidating insertions at the same location.  */
   3528 
   3529 static void
   3530 test_one_liner_many_fixits_1 ()
   3531 {
   3532   test_diagnostic_context dc;
   3533   location_t equals = linemap_position_for_column (line_table, 5);
   3534   rich_location richloc (line_table, equals);
   3535   for (int i = 0; i < 19; i++)
   3536     richloc.add_fixit_insert_before ("a");
   3537   ASSERT_EQ (1, richloc.get_num_fixit_hints ());
   3538   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3539   ASSERT_STREQ (" foo = bar.field;\n"
   3540 		"     ^\n"
   3541 		"     aaaaaaaaaaaaaaaaaaa\n",
   3542 		pp_formatted_text (dc.printer));
   3543 }
   3544 
   3545 /* Ensure that we can add an arbitrary number of fix-it hints to a
   3546    rich_location, even if they are not consolidated.  */
   3547 
   3548 static void
   3549 test_one_liner_many_fixits_2 ()
   3550 {
   3551   test_diagnostic_context dc;
   3552   location_t equals = linemap_position_for_column (line_table, 5);
   3553   rich_location richloc (line_table, equals);
   3554   for (int i = 0; i < 19; i++)
   3555     {
   3556       location_t loc = linemap_position_for_column (line_table, (i * 2) + 1);
   3557       richloc.add_fixit_insert_before (loc, "a");
   3558     }
   3559   ASSERT_EQ (19, richloc.get_num_fixit_hints ());
   3560   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3561   ASSERT_STREQ (" foo = bar.field;\n"
   3562 		"     ^\n"
   3563 		" a a a a a a a a a a a a a a a a a a a\n",
   3564 		pp_formatted_text (dc.printer));
   3565 }
   3566 
   3567 /* Test of labeling the ranges within a rich_location.  */
   3568 
   3569 static void
   3570 test_one_liner_labels ()
   3571 {
   3572   location_t foo
   3573     = make_location (linemap_position_for_column (line_table, 1),
   3574 		     linemap_position_for_column (line_table, 1),
   3575 		     linemap_position_for_column (line_table, 3));
   3576   location_t bar
   3577     = make_location (linemap_position_for_column (line_table, 7),
   3578 		     linemap_position_for_column (line_table, 7),
   3579 		     linemap_position_for_column (line_table, 9));
   3580   location_t field
   3581     = make_location (linemap_position_for_column (line_table, 11),
   3582 		     linemap_position_for_column (line_table, 11),
   3583 		     linemap_position_for_column (line_table, 15));
   3584 
   3585   /* Example where all the labels fit on one line.  */
   3586   {
   3587     text_range_label label0 ("0");
   3588     text_range_label label1 ("1");
   3589     text_range_label label2 ("2");
   3590     gcc_rich_location richloc (foo, &label0);
   3591     richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
   3592     richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
   3593 
   3594     {
   3595       test_diagnostic_context dc;
   3596       diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3597       ASSERT_STREQ (" foo = bar.field;\n"
   3598 		    " ^~~   ~~~ ~~~~~\n"
   3599 		    " |     |   |\n"
   3600 		    " 0     1   2\n",
   3601 		    pp_formatted_text (dc.printer));
   3602     }
   3603 
   3604     /* Verify that we can disable label-printing.  */
   3605     {
   3606       test_diagnostic_context dc;
   3607       dc.show_labels_p = false;
   3608       diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3609       ASSERT_STREQ (" foo = bar.field;\n"
   3610 		    " ^~~   ~~~ ~~~~~\n",
   3611 		    pp_formatted_text (dc.printer));
   3612     }
   3613   }
   3614 
   3615   /* Example where the labels need extra lines.  */
   3616   {
   3617     text_range_label label0 ("label 0");
   3618     text_range_label label1 ("label 1");
   3619     text_range_label label2 ("label 2");
   3620     gcc_rich_location richloc (foo, &label0);
   3621     richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
   3622     richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
   3623 
   3624     test_diagnostic_context dc;
   3625     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3626     ASSERT_STREQ (" foo = bar.field;\n"
   3627 		  " ^~~   ~~~ ~~~~~\n"
   3628 		  " |     |   |\n"
   3629 		  " |     |   label 2\n"
   3630 		  " |     label 1\n"
   3631 		  " label 0\n",
   3632 		  pp_formatted_text (dc.printer));
   3633   }
   3634 
   3635   /* Example of boundary conditions: label 0 and 1 have just enough clearance,
   3636      but label 1 just touches label 2.  */
   3637   {
   3638     text_range_label label0 ("aaaaa");
   3639     text_range_label label1 ("bbbb");
   3640     text_range_label label2 ("c");
   3641     gcc_rich_location richloc (foo, &label0);
   3642     richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
   3643     richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
   3644 
   3645     test_diagnostic_context dc;
   3646     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3647     ASSERT_STREQ (" foo = bar.field;\n"
   3648 		  " ^~~   ~~~ ~~~~~\n"
   3649 		  " |     |   |\n"
   3650 		  " |     |   c\n"
   3651 		  " aaaaa bbbb\n",
   3652 		  pp_formatted_text (dc.printer));
   3653   }
   3654 
   3655   /* Example of out-of-order ranges (thus requiring a sort).  */
   3656   {
   3657     text_range_label label0 ("0");
   3658     text_range_label label1 ("1");
   3659     text_range_label label2 ("2");
   3660     gcc_rich_location richloc (field, &label0);
   3661     richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
   3662     richloc.add_range (foo, SHOW_RANGE_WITHOUT_CARET, &label2);
   3663 
   3664     test_diagnostic_context dc;
   3665     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3666     ASSERT_STREQ (" foo = bar.field;\n"
   3667 		  " ~~~   ~~~ ^~~~~\n"
   3668 		  " |     |   |\n"
   3669 		  " 2     1   0\n",
   3670 		  pp_formatted_text (dc.printer));
   3671   }
   3672 
   3673   /* Ensure we don't ICE if multiple ranges with labels are on
   3674      the same point.  */
   3675   {
   3676     text_range_label label0 ("label 0");
   3677     text_range_label label1 ("label 1");
   3678     text_range_label label2 ("label 2");
   3679     gcc_rich_location richloc (bar, &label0);
   3680     richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
   3681     richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label2);
   3682 
   3683     test_diagnostic_context dc;
   3684     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3685     ASSERT_STREQ (" foo = bar.field;\n"
   3686 		  "       ^~~\n"
   3687 		  "       |\n"
   3688 		  "       label 0\n"
   3689 		  "       label 1\n"
   3690 		  "       label 2\n",
   3691 		  pp_formatted_text (dc.printer));
   3692   }
   3693 
   3694   /* Example of out-of-order ranges (thus requiring a sort), where
   3695      they overlap, and there are multiple ranges on the same point.  */
   3696   {
   3697     text_range_label label_0a ("label 0a");
   3698     text_range_label label_1a ("label 1a");
   3699     text_range_label label_2a ("label 2a");
   3700     text_range_label label_0b ("label 0b");
   3701     text_range_label label_1b ("label 1b");
   3702     text_range_label label_2b ("label 2b");
   3703     text_range_label label_0c ("label 0c");
   3704     text_range_label label_1c ("label 1c");
   3705     text_range_label label_2c ("label 2c");
   3706     gcc_rich_location richloc (field, &label_0a);
   3707     richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label_1a);
   3708     richloc.add_range (foo, SHOW_RANGE_WITHOUT_CARET, &label_2a);
   3709 
   3710     richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label_0b);
   3711     richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label_1b);
   3712     richloc.add_range (foo, SHOW_RANGE_WITHOUT_CARET, &label_2b);
   3713 
   3714     richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label_0c);
   3715     richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label_1c);
   3716     richloc.add_range (foo, SHOW_RANGE_WITHOUT_CARET, &label_2c);
   3717 
   3718     test_diagnostic_context dc;
   3719     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3720     ASSERT_STREQ (" foo = bar.field;\n"
   3721 		  " ~~~   ~~~ ^~~~~\n"
   3722 		  " |     |   |\n"
   3723 		  " |     |   label 0a\n"
   3724 		  " |     |   label 0b\n"
   3725 		  " |     |   label 0c\n"
   3726 		  " |     label 1a\n"
   3727 		  " |     label 1b\n"
   3728 		  " |     label 1c\n"
   3729 		  " label 2a\n"
   3730 		  " label 2b\n"
   3731 		  " label 2c\n",
   3732 		  pp_formatted_text (dc.printer));
   3733   }
   3734 
   3735   /* Verify that a NULL result from range_label::get_text is
   3736      handled gracefully.  */
   3737   {
   3738     text_range_label label (NULL);
   3739     gcc_rich_location richloc (bar, &label);
   3740 
   3741     test_diagnostic_context dc;
   3742     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3743     ASSERT_STREQ (" foo = bar.field;\n"
   3744 		  "       ^~~\n",
   3745 		  pp_formatted_text (dc.printer));
   3746    }
   3747 
   3748   /* TODO: example of formatted printing (needs to be in
   3749      gcc-rich-location.cc due to Makefile.in issues).  */
   3750 }
   3751 
   3752 /* Run the various one-liner tests.  */
   3753 
   3754 static void
   3755 test_diagnostic_show_locus_one_liner (const line_table_case &case_)
   3756 {
   3757   /* Create a tempfile and write some text to it.
   3758      ....................0000000001111111.
   3759      ....................1234567890123456.  */
   3760   const char *content = "foo = bar.field;\n";
   3761   temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
   3762   line_table_test ltt (case_);
   3763 
   3764   linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
   3765 
   3766   location_t line_end = linemap_position_for_column (line_table, 16);
   3767 
   3768   /* Don't attempt to run the tests if column data might be unavailable.  */
   3769   if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
   3770     return;
   3771 
   3772   ASSERT_STREQ (tmp.get_filename (), LOCATION_FILE (line_end));
   3773   ASSERT_EQ (1, LOCATION_LINE (line_end));
   3774   ASSERT_EQ (16, LOCATION_COLUMN (line_end));
   3775 
   3776   test_one_liner_simple_caret ();
   3777   test_one_liner_caret_and_range ();
   3778   test_one_liner_multiple_carets_and_ranges ();
   3779   test_one_liner_fixit_insert_before ();
   3780   test_one_liner_fixit_insert_after ();
   3781   test_one_liner_fixit_remove ();
   3782   test_one_liner_fixit_replace ();
   3783   test_one_liner_fixit_replace_non_equal_range ();
   3784   test_one_liner_fixit_replace_equal_secondary_range ();
   3785   test_one_liner_fixit_validation_adhoc_locations ();
   3786   test_one_liner_many_fixits_1 ();
   3787   test_one_liner_many_fixits_2 ();
   3788   test_one_liner_labels ();
   3789 }
   3790 
   3791 /* Version of all one-liner tests exercising multibyte awareness.  For
   3792    simplicity we stick to using two multibyte characters in the test, U+1F602
   3793    == "\xf0\x9f\x98\x82", which uses 4 bytes and 2 display columns, and U+03C0
   3794    == "\xcf\x80", which uses 2 bytes and 1 display column.  Note: all of the
   3795    below asserts would be easier to read if we used UTF-8 directly in the
   3796    string constants, but it seems better not to demand the host compiler
   3797    support this, when it isn't otherwise necessary.  Instead, whenever an
   3798    extended character appears in a string, we put a line break after it so that
   3799    all succeeding characters can appear visually at the correct display column.
   3800 
   3801    All of these work on the following 1-line source file:
   3802 
   3803      .0000000001111111111222222   display
   3804      .1234567890123456789012345   columns
   3805      "SS_foo = P_bar.SS_fieldP;\n"
   3806      .0000000111111111222222223   byte
   3807      .1356789012456789134567891   columns
   3808 
   3809    which is set up by test_diagnostic_show_locus_one_liner and calls
   3810    them.  Here SS represents the two display columns for the U+1F602 emoji and
   3811    P represents the one display column for the U+03C0 pi symbol.  */
   3812 
   3813 /* Just a caret.  */
   3814 
   3815 static void
   3816 test_one_liner_simple_caret_utf8 ()
   3817 {
   3818   test_diagnostic_context dc;
   3819   location_t caret = linemap_position_for_column (line_table, 18);
   3820   rich_location richloc (line_table, caret);
   3821   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3822   ASSERT_STREQ (" \xf0\x9f\x98\x82"
   3823 		   "_foo = \xcf\x80"
   3824 			   "_bar.\xf0\x9f\x98\x82"
   3825 				  "_field\xcf\x80"
   3826 					 ";\n"
   3827 		"               ^\n",
   3828 		pp_formatted_text (dc.printer));
   3829 }
   3830 
   3831 /* Caret and range.  */
   3832 static void
   3833 test_one_liner_caret_and_range_utf8 ()
   3834 {
   3835   test_diagnostic_context dc;
   3836   location_t caret = linemap_position_for_column (line_table, 18);
   3837   location_t start = linemap_position_for_column (line_table, 12);
   3838   location_t finish = linemap_position_for_column (line_table, 30);
   3839   location_t loc = make_location (caret, start, finish);
   3840   rich_location richloc (line_table, loc);
   3841   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3842   ASSERT_STREQ (" \xf0\x9f\x98\x82"
   3843 		   "_foo = \xcf\x80"
   3844 			   "_bar.\xf0\x9f\x98\x82"
   3845 				  "_field\xcf\x80"
   3846 					 ";\n"
   3847 		"          ~~~~~^~~~~~~~~~\n",
   3848 		pp_formatted_text (dc.printer));
   3849 }
   3850 
   3851 /* Multiple ranges and carets.  */
   3852 
   3853 static void
   3854 test_one_liner_multiple_carets_and_ranges_utf8 ()
   3855 {
   3856   test_diagnostic_context dc;
   3857   location_t foo
   3858     = make_location (linemap_position_for_column (line_table, 7),
   3859 		     linemap_position_for_column (line_table, 1),
   3860 		     linemap_position_for_column (line_table, 8));
   3861   dc.caret_chars[0] = 'A';
   3862 
   3863   location_t bar
   3864     = make_location (linemap_position_for_column (line_table, 16),
   3865 		     linemap_position_for_column (line_table, 12),
   3866 		     linemap_position_for_column (line_table, 17));
   3867   dc.caret_chars[1] = 'B';
   3868 
   3869   location_t field
   3870     = make_location (linemap_position_for_column (line_table, 26),
   3871 		     linemap_position_for_column (line_table, 19),
   3872 		     linemap_position_for_column (line_table, 30));
   3873   dc.caret_chars[2] = 'C';
   3874   rich_location richloc (line_table, foo);
   3875   richloc.add_range (bar, SHOW_RANGE_WITH_CARET);
   3876   richloc.add_range (field, SHOW_RANGE_WITH_CARET);
   3877   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3878   ASSERT_STREQ (" \xf0\x9f\x98\x82"
   3879 		   "_foo = \xcf\x80"
   3880 			   "_bar.\xf0\x9f\x98\x82"
   3881 				  "_field\xcf\x80"
   3882 					 ";\n"
   3883 		" ~~~~A~   ~~~B~ ~~~~~C~~~\n",
   3884 		pp_formatted_text (dc.printer));
   3885 }
   3886 
   3887 /* Insertion fix-it hint: adding an "&" to the front of "P_bar.field". */
   3888 
   3889 static void
   3890 test_one_liner_fixit_insert_before_utf8 ()
   3891 {
   3892   test_diagnostic_context dc;
   3893   location_t caret = linemap_position_for_column (line_table, 12);
   3894   rich_location richloc (line_table, caret);
   3895   richloc.add_fixit_insert_before ("&");
   3896   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3897   ASSERT_STREQ (" \xf0\x9f\x98\x82"
   3898 		   "_foo = \xcf\x80"
   3899 			   "_bar.\xf0\x9f\x98\x82"
   3900 				  "_field\xcf\x80"
   3901 					 ";\n"
   3902 		"          ^\n"
   3903 		"          &\n",
   3904 		pp_formatted_text (dc.printer));
   3905 }
   3906 
   3907 /* Insertion fix-it hint: adding a "[0]" after "SS_foo". */
   3908 
   3909 static void
   3910 test_one_liner_fixit_insert_after_utf8 ()
   3911 {
   3912   test_diagnostic_context dc;
   3913   location_t start = linemap_position_for_column (line_table, 1);
   3914   location_t finish = linemap_position_for_column (line_table, 8);
   3915   location_t foo = make_location (start, start, finish);
   3916   rich_location richloc (line_table, foo);
   3917   richloc.add_fixit_insert_after ("[0]");
   3918   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3919   ASSERT_STREQ (" \xf0\x9f\x98\x82"
   3920 		   "_foo = \xcf\x80"
   3921 			   "_bar.\xf0\x9f\x98\x82"
   3922 				  "_field\xcf\x80"
   3923 					 ";\n"
   3924 		" ^~~~~~\n"
   3925 		"       [0]\n",
   3926 		pp_formatted_text (dc.printer));
   3927 }
   3928 
   3929 /* Removal fix-it hint: removal of the ".SS_fieldP". */
   3930 
   3931 static void
   3932 test_one_liner_fixit_remove_utf8 ()
   3933 {
   3934   test_diagnostic_context dc;
   3935   location_t start = linemap_position_for_column (line_table, 18);
   3936   location_t finish = linemap_position_for_column (line_table, 30);
   3937   location_t dot = make_location (start, start, finish);
   3938   rich_location richloc (line_table, dot);
   3939   richloc.add_fixit_remove ();
   3940   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3941   ASSERT_STREQ (" \xf0\x9f\x98\x82"
   3942 		   "_foo = \xcf\x80"
   3943 			   "_bar.\xf0\x9f\x98\x82"
   3944 				  "_field\xcf\x80"
   3945 					 ";\n"
   3946 		"               ^~~~~~~~~~\n"
   3947 		"               ----------\n",
   3948 		pp_formatted_text (dc.printer));
   3949 }
   3950 
   3951 /* Replace fix-it hint: replacing "SS_fieldP" with "m_SSfieldP". */
   3952 
   3953 static void
   3954 test_one_liner_fixit_replace_utf8 ()
   3955 {
   3956   test_diagnostic_context dc;
   3957   location_t start = linemap_position_for_column (line_table, 19);
   3958   location_t finish = linemap_position_for_column (line_table, 30);
   3959   location_t field = make_location (start, start, finish);
   3960   rich_location richloc (line_table, field);
   3961   richloc.add_fixit_replace ("m_\xf0\x9f\x98\x82_field\xcf\x80");
   3962   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3963   ASSERT_STREQ (" \xf0\x9f\x98\x82"
   3964 		   "_foo = \xcf\x80"
   3965 			   "_bar.\xf0\x9f\x98\x82"
   3966 				  "_field\xcf\x80"
   3967 					 ";\n"
   3968 		"                ^~~~~~~~~\n"
   3969 		"                m_\xf0\x9f\x98\x82"
   3970 				    "_field\xcf\x80\n",
   3971 		pp_formatted_text (dc.printer));
   3972 }
   3973 
   3974 /* Replace fix-it hint: replacing "SS_fieldP" with "m_SSfieldP",
   3975    but where the caret was elsewhere.  */
   3976 
   3977 static void
   3978 test_one_liner_fixit_replace_non_equal_range_utf8 ()
   3979 {
   3980   test_diagnostic_context dc;
   3981   location_t equals = linemap_position_for_column (line_table, 10);
   3982   location_t start = linemap_position_for_column (line_table, 19);
   3983   location_t finish = linemap_position_for_column (line_table, 30);
   3984   rich_location richloc (line_table, equals);
   3985   source_range range;
   3986   range.m_start = start;
   3987   range.m_finish = finish;
   3988   richloc.add_fixit_replace (range, "m_\xf0\x9f\x98\x82_field\xcf\x80");
   3989   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   3990   /* The replacement range is not indicated in the annotation line, so
   3991      it should be indicated via an additional underline.  */
   3992   ASSERT_STREQ (" \xf0\x9f\x98\x82"
   3993 		   "_foo = \xcf\x80"
   3994 			   "_bar.\xf0\x9f\x98\x82"
   3995 				  "_field\xcf\x80"
   3996 					 ";\n"
   3997 		"        ^\n"
   3998 		"                ---------\n"
   3999 		"                m_\xf0\x9f\x98\x82"
   4000 				    "_field\xcf\x80\n",
   4001 		pp_formatted_text (dc.printer));
   4002 }
   4003 
   4004 /* Replace fix-it hint: replacing "SS_fieldP" with "m_SSfieldP",
   4005    where the caret was elsewhere, but where a secondary range
   4006    exactly covers "field".  */
   4007 
   4008 static void
   4009 test_one_liner_fixit_replace_equal_secondary_range_utf8 ()
   4010 {
   4011   test_diagnostic_context dc;
   4012   location_t equals = linemap_position_for_column (line_table, 10);
   4013   location_t start = linemap_position_for_column (line_table, 19);
   4014   location_t finish = linemap_position_for_column (line_table, 30);
   4015   rich_location richloc (line_table, equals);
   4016   location_t field = make_location (start, start, finish);
   4017   richloc.add_range (field);
   4018   richloc.add_fixit_replace (field, "m_\xf0\x9f\x98\x82_field\xcf\x80");
   4019   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4020   /* The replacement range is indicated in the annotation line,
   4021      so it shouldn't be indicated via an additional underline.  */
   4022   ASSERT_STREQ (" \xf0\x9f\x98\x82"
   4023 		   "_foo = \xcf\x80"
   4024 			   "_bar.\xf0\x9f\x98\x82"
   4025 				  "_field\xcf\x80"
   4026 					 ";\n"
   4027 		"        ^       ~~~~~~~~~\n"
   4028 		"                m_\xf0\x9f\x98\x82"
   4029 				    "_field\xcf\x80\n",
   4030 		pp_formatted_text (dc.printer));
   4031 }
   4032 
   4033 /* Verify that we can use ad-hoc locations when adding fixits to a
   4034    rich_location.  */
   4035 
   4036 static void
   4037 test_one_liner_fixit_validation_adhoc_locations_utf8 ()
   4038 {
   4039   /* Generate a range that's too long to be packed, so must
   4040      be stored as an ad-hoc location (given the defaults
   4041      of 5 bits or 0 bits of packed range); 41 columns > 2**5.  */
   4042   const location_t c12 = linemap_position_for_column (line_table, 12);
   4043   const location_t c52 = linemap_position_for_column (line_table, 52);
   4044   const location_t loc = make_location (c12, c12, c52);
   4045 
   4046   if (c52 > LINE_MAP_MAX_LOCATION_WITH_COLS)
   4047     return;
   4048 
   4049   ASSERT_TRUE (IS_ADHOC_LOC (loc));
   4050 
   4051   /* Insert.  */
   4052   {
   4053     rich_location richloc (line_table, loc);
   4054     richloc.add_fixit_insert_before (loc, "test");
   4055     /* It should not have been discarded by the validator.  */
   4056     ASSERT_EQ (1, richloc.get_num_fixit_hints ());
   4057 
   4058     test_diagnostic_context dc;
   4059     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4060     ASSERT_STREQ (" \xf0\x9f\x98\x82"
   4061 		     "_foo = \xcf\x80"
   4062 			     "_bar.\xf0\x9f\x98\x82"
   4063 				    "_field\xcf\x80"
   4064 					   ";\n"
   4065 		  "          ^~~~~~~~~~~~~~~~                     \n"
   4066 		  "          test\n",
   4067 		pp_formatted_text (dc.printer));
   4068   }
   4069 
   4070   /* Remove.  */
   4071   {
   4072     rich_location richloc (line_table, loc);
   4073     source_range range = source_range::from_locations (loc, c52);
   4074     richloc.add_fixit_remove (range);
   4075     /* It should not have been discarded by the validator.  */
   4076     ASSERT_EQ (1, richloc.get_num_fixit_hints ());
   4077 
   4078     test_diagnostic_context dc;
   4079     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4080     ASSERT_STREQ (" \xf0\x9f\x98\x82"
   4081 		     "_foo = \xcf\x80"
   4082 			     "_bar.\xf0\x9f\x98\x82"
   4083 				    "_field\xcf\x80"
   4084 					   ";\n"
   4085 		  "          ^~~~~~~~~~~~~~~~                     \n"
   4086 		  "          -------------------------------------\n",
   4087 		pp_formatted_text (dc.printer));
   4088   }
   4089 
   4090   /* Replace.  */
   4091   {
   4092     rich_location richloc (line_table, loc);
   4093     source_range range = source_range::from_locations (loc, c52);
   4094     richloc.add_fixit_replace (range, "test");
   4095     /* It should not have been discarded by the validator.  */
   4096     ASSERT_EQ (1, richloc.get_num_fixit_hints ());
   4097 
   4098     test_diagnostic_context dc;
   4099     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4100     ASSERT_STREQ (" \xf0\x9f\x98\x82"
   4101 		     "_foo = \xcf\x80"
   4102 			     "_bar.\xf0\x9f\x98\x82"
   4103 				    "_field\xcf\x80"
   4104 					   ";\n"
   4105 		  "          ^~~~~~~~~~~~~~~~                     \n"
   4106 		  "          test\n",
   4107 		pp_formatted_text (dc.printer));
   4108   }
   4109 }
   4110 
   4111 /* Test of consolidating insertions at the same location.  */
   4112 
   4113 static void
   4114 test_one_liner_many_fixits_1_utf8 ()
   4115 {
   4116   test_diagnostic_context dc;
   4117   location_t equals = linemap_position_for_column (line_table, 10);
   4118   rich_location richloc (line_table, equals);
   4119   for (int i = 0; i < 19; i++)
   4120     richloc.add_fixit_insert_before (i & 1 ? "@" : "\xcf\x80");
   4121   ASSERT_EQ (1, richloc.get_num_fixit_hints ());
   4122   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4123   ASSERT_STREQ (" \xf0\x9f\x98\x82"
   4124 		   "_foo = \xcf\x80"
   4125 			   "_bar.\xf0\x9f\x98\x82"
   4126 				  "_field\xcf\x80"
   4127 					 ";\n"
   4128 		"        ^\n"
   4129 		"        \xcf\x80@\xcf\x80@\xcf\x80@\xcf\x80@\xcf\x80@"
   4130 		"\xcf\x80@\xcf\x80@\xcf\x80@\xcf\x80@\xcf\x80\n",
   4131 		pp_formatted_text (dc.printer));
   4132 }
   4133 
   4134 /* Ensure that we can add an arbitrary number of fix-it hints to a
   4135    rich_location, even if they are not consolidated.  */
   4136 
   4137 static void
   4138 test_one_liner_many_fixits_2_utf8 ()
   4139 {
   4140   test_diagnostic_context dc;
   4141   location_t equals = linemap_position_for_column (line_table, 10);
   4142   rich_location richloc (line_table, equals);
   4143   const int nlocs = 19;
   4144   int locs[nlocs] = {1, 5, 7, 9, 11, 14, 16, 18, 23, 25, 27, 29, 32,
   4145 		     34, 36, 38, 40, 42, 44};
   4146   for (int i = 0; i != nlocs; ++i)
   4147     {
   4148       location_t loc = linemap_position_for_column (line_table, locs[i]);
   4149       richloc.add_fixit_insert_before (loc, i & 1 ? "@" : "\xcf\x80");
   4150     }
   4151 
   4152   ASSERT_EQ (nlocs, richloc.get_num_fixit_hints ());
   4153   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4154   ASSERT_STREQ (" \xf0\x9f\x98\x82"
   4155 		   "_foo = \xcf\x80"
   4156 			   "_bar.\xf0\x9f\x98\x82"
   4157 				  "_field\xcf\x80"
   4158 					 ";\n"
   4159 		"        ^\n"
   4160 		" \xcf\x80 @ \xcf\x80 @ \xcf\x80 @ \xcf\x80 @  \xcf\x80 @"
   4161 		" \xcf\x80 @ \xcf\x80 @ \xcf\x80 @ \xcf\x80 @ \xcf\x80\n",
   4162 		pp_formatted_text (dc.printer));
   4163 }
   4164 
   4165 /* Test of labeling the ranges within a rich_location.  */
   4166 
   4167 static void
   4168 test_one_liner_labels_utf8 ()
   4169 {
   4170   location_t foo
   4171     = make_location (linemap_position_for_column (line_table, 1),
   4172 		     linemap_position_for_column (line_table, 1),
   4173 		     linemap_position_for_column (line_table, 8));
   4174   location_t bar
   4175     = make_location (linemap_position_for_column (line_table, 12),
   4176 		     linemap_position_for_column (line_table, 12),
   4177 		     linemap_position_for_column (line_table, 17));
   4178   location_t field
   4179     = make_location (linemap_position_for_column (line_table, 19),
   4180 		     linemap_position_for_column (line_table, 19),
   4181 		     linemap_position_for_column (line_table, 30));
   4182 
   4183   /* Example where all the labels fit on one line.  */
   4184   {
   4185     /* These three labels contain multibyte characters such that their byte
   4186        lengths are respectively (12, 10, 18), but their display widths are only
   4187        (6, 5, 9).  All three fit on the line when considering the display
   4188        widths, but not when considering the byte widths, so verify that we do
   4189        indeed put them all on one line.  */
   4190     text_range_label label0
   4191       ("\xcf\x80\xcf\x80\xcf\x80\xcf\x80\xcf\x80\xcf\x80");
   4192     text_range_label label1
   4193       ("\xf0\x9f\x98\x82\xf0\x9f\x98\x82\xcf\x80");
   4194     text_range_label label2
   4195       ("\xf0\x9f\x98\x82\xcf\x80\xf0\x9f\x98\x82\xf0\x9f\x98\x82\xcf\x80"
   4196        "\xcf\x80");
   4197     gcc_rich_location richloc (foo, &label0);
   4198     richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
   4199     richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
   4200 
   4201     {
   4202       test_diagnostic_context dc;
   4203       diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4204       ASSERT_STREQ (" \xf0\x9f\x98\x82"
   4205 		       "_foo = \xcf\x80"
   4206 			       "_bar.\xf0\x9f\x98\x82"
   4207 				      "_field\xcf\x80"
   4208 					     ";\n"
   4209 		    " ^~~~~~   ~~~~~ ~~~~~~~~~\n"
   4210 		    " |        |     |\n"
   4211 		    " \xcf\x80\xcf\x80\xcf\x80\xcf\x80\xcf\x80\xcf\x80"
   4212 			   "   \xf0\x9f\x98\x82\xf0\x9f\x98\x82\xcf\x80"
   4213 				   " \xf0\x9f\x98\x82\xcf\x80\xf0\x9f\x98\x82"
   4214 					 "\xf0\x9f\x98\x82\xcf\x80\xcf\x80\n",
   4215 		    pp_formatted_text (dc.printer));
   4216     }
   4217 
   4218   }
   4219 
   4220   /* Example where the labels need extra lines.  */
   4221   {
   4222     text_range_label label0 ("label 0\xf0\x9f\x98\x82");
   4223     text_range_label label1 ("label 1\xcf\x80");
   4224     text_range_label label2 ("label 2\xcf\x80");
   4225     gcc_rich_location richloc (foo, &label0);
   4226     richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
   4227     richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
   4228 
   4229     test_diagnostic_context dc;
   4230     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4231 
   4232     ASSERT_STREQ (" \xf0\x9f\x98\x82"
   4233 		     "_foo = \xcf\x80"
   4234 			     "_bar.\xf0\x9f\x98\x82"
   4235 				    "_field\xcf\x80"
   4236 					   ";\n"
   4237 		  " ^~~~~~   ~~~~~ ~~~~~~~~~\n"
   4238 		  " |        |     |\n"
   4239 		  " |        |     label 2\xcf\x80\n"
   4240 		  " |        label 1\xcf\x80\n"
   4241 		  " label 0\xf0\x9f\x98\x82\n",
   4242 		  pp_formatted_text (dc.printer));
   4243   }
   4244 
   4245   /* Example of boundary conditions: label 0 and 1 have just enough clearance,
   4246      but label 1 just touches label 2.  */
   4247   {
   4248     text_range_label label0 ("aaaaa\xf0\x9f\x98\x82\xcf\x80");
   4249     text_range_label label1 ("bb\xf0\x9f\x98\x82\xf0\x9f\x98\x82");
   4250     text_range_label label2 ("c");
   4251     gcc_rich_location richloc (foo, &label0);
   4252     richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
   4253     richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
   4254 
   4255     test_diagnostic_context dc;
   4256     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4257     ASSERT_STREQ (" \xf0\x9f\x98\x82"
   4258 		     "_foo = \xcf\x80"
   4259 			     "_bar.\xf0\x9f\x98\x82"
   4260 				    "_field\xcf\x80"
   4261 					   ";\n"
   4262 		  " ^~~~~~   ~~~~~ ~~~~~~~~~\n"
   4263 		  " |        |     |\n"
   4264 		  " |        |     c\n"
   4265 		  " aaaaa\xf0\x9f\x98\x82\xcf\x80"
   4266 			   " bb\xf0\x9f\x98\x82\xf0\x9f\x98\x82\n",
   4267 		  pp_formatted_text (dc.printer));
   4268   }
   4269 
   4270   /* Example of escaping the source lines.  */
   4271   {
   4272     text_range_label label0 ("label 0\xf0\x9f\x98\x82");
   4273     text_range_label label1 ("label 1\xcf\x80");
   4274     text_range_label label2 ("label 2\xcf\x80");
   4275     gcc_rich_location richloc (foo, &label0);
   4276     richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
   4277     richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
   4278     richloc.set_escape_on_output (true);
   4279 
   4280     {
   4281       test_diagnostic_context dc;
   4282       dc.escape_format = DIAGNOSTICS_ESCAPE_FORMAT_UNICODE;
   4283       diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4284       ASSERT_STREQ (" <U+1F602>_foo = <U+03C0>_bar.<U+1F602>_field<U+03C0>;\n"
   4285 		    " ^~~~~~~~~~~~~   ~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~\n"
   4286 		    " |               |            |\n"
   4287 		    " |               |            label 2\xcf\x80\n"
   4288 		    " |               label 1\xcf\x80\n"
   4289 		    " label 0\xf0\x9f\x98\x82\n",
   4290 		    pp_formatted_text (dc.printer));
   4291     }
   4292     {
   4293       test_diagnostic_context dc;
   4294       dc.escape_format = DIAGNOSTICS_ESCAPE_FORMAT_BYTES;
   4295       diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4296       ASSERT_STREQ
   4297 	(" <f0><9f><98><82>_foo = <cf><80>_bar.<f0><9f><98><82>_field<cf><80>;\n"
   4298 	 " ^~~~~~~~~~~~~~~~~~~~   ~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
   4299 	 " |                      |            |\n"
   4300 	 " |                      |            label 2\xcf\x80\n"
   4301 	 " |                      label 1\xcf\x80\n"
   4302 	 " label 0\xf0\x9f\x98\x82\n",
   4303 	 pp_formatted_text (dc.printer));
   4304     }
   4305   }
   4306 }
   4307 
   4308 /* Make sure that colorization codes don't interrupt a multibyte
   4309    sequence, which would corrupt it.  */
   4310 static void
   4311 test_one_liner_colorized_utf8 ()
   4312 {
   4313   test_diagnostic_context dc;
   4314   dc.colorize_source_p = true;
   4315   diagnostic_color_init (&dc, DIAGNOSTICS_COLOR_YES);
   4316   const location_t pi = linemap_position_for_column (line_table, 12);
   4317   rich_location richloc (line_table, pi);
   4318   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4319 
   4320   /* In order to avoid having the test depend on exactly how the colorization
   4321      was effected, just confirm there are two pi characters in the output.  */
   4322   const char *result = pp_formatted_text (dc.printer);
   4323   const char *null_term = result + strlen (result);
   4324   const char *first_pi = strstr (result, "\xcf\x80");
   4325   ASSERT_TRUE (first_pi && first_pi <= null_term - 2);
   4326   ASSERT_STR_CONTAINS (first_pi + 2, "\xcf\x80");
   4327 }
   4328 
   4329 /* Run the various one-liner tests.  */
   4330 
   4331 static void
   4332 test_diagnostic_show_locus_one_liner_utf8 (const line_table_case &case_)
   4333 {
   4334   /* Create a tempfile and write some text to it.  */
   4335   const char *content
   4336     /* Display columns.
   4337        0000000000000000000000011111111111111111111111111111112222222222222
   4338        1111111122222222345678900000000123456666666677777777890123444444445  */
   4339     = "\xf0\x9f\x98\x82_foo = \xcf\x80_bar.\xf0\x9f\x98\x82_field\xcf\x80;\n";
   4340     /* 0000000000000000000001111111111111111111222222222222222222222233333
   4341        1111222233334444567890122223333456789999000011112222345678999900001
   4342        Byte columns.  */
   4343   temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
   4344   line_table_test ltt (case_);
   4345 
   4346   linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
   4347 
   4348   location_t line_end = linemap_position_for_column (line_table, 31);
   4349 
   4350   /* Don't attempt to run the tests if column data might be unavailable.  */
   4351   if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
   4352     return;
   4353 
   4354   ASSERT_STREQ (tmp.get_filename (), LOCATION_FILE (line_end));
   4355   ASSERT_EQ (1, LOCATION_LINE (line_end));
   4356   ASSERT_EQ (31, LOCATION_COLUMN (line_end));
   4357 
   4358   char_span lspan = location_get_source_line (tmp.get_filename (), 1);
   4359   ASSERT_EQ (25, cpp_display_width (lspan.get_buffer (), lspan.length (),
   4360 				    def_policy ()));
   4361   ASSERT_EQ (25, location_compute_display_column (expand_location (line_end),
   4362 						  def_policy ()));
   4363 
   4364   test_one_liner_simple_caret_utf8 ();
   4365   test_one_liner_caret_and_range_utf8 ();
   4366   test_one_liner_multiple_carets_and_ranges_utf8 ();
   4367   test_one_liner_fixit_insert_before_utf8 ();
   4368   test_one_liner_fixit_insert_after_utf8 ();
   4369   test_one_liner_fixit_remove_utf8 ();
   4370   test_one_liner_fixit_replace_utf8 ();
   4371   test_one_liner_fixit_replace_non_equal_range_utf8 ();
   4372   test_one_liner_fixit_replace_equal_secondary_range_utf8 ();
   4373   test_one_liner_fixit_validation_adhoc_locations_utf8 ();
   4374   test_one_liner_many_fixits_1_utf8 ();
   4375   test_one_liner_many_fixits_2_utf8 ();
   4376   test_one_liner_labels_utf8 ();
   4377   test_one_liner_colorized_utf8 ();
   4378 }
   4379 
   4380 /* Verify that gcc_rich_location::add_location_if_nearby works.  */
   4381 
   4382 static void
   4383 test_add_location_if_nearby (const line_table_case &case_)
   4384 {
   4385   /* Create a tempfile and write some text to it.
   4386      ...000000000111111111122222222223333333333.
   4387      ...123456789012345678901234567890123456789.  */
   4388   const char *content
   4389     = ("struct same_line { double x; double y; ;\n" /* line 1.  */
   4390        "struct different_line\n"                    /* line 2.  */
   4391        "{\n"                                        /* line 3.  */
   4392        "  double x;\n"                              /* line 4.  */
   4393        "  double y;\n"                              /* line 5.  */
   4394        ";\n");                                      /* line 6.  */
   4395   temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
   4396   line_table_test ltt (case_);
   4397 
   4398   const line_map_ordinary *ord_map
   4399     = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
   4400 					   tmp.get_filename (), 0));
   4401 
   4402   linemap_line_start (line_table, 1, 100);
   4403 
   4404   const location_t final_line_end
   4405     = linemap_position_for_line_and_column (line_table, ord_map, 6, 7);
   4406 
   4407   /* Don't attempt to run the tests if column data might be unavailable.  */
   4408   if (final_line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
   4409     return;
   4410 
   4411   /* Test of add_location_if_nearby on the same line as the
   4412      primary location.  */
   4413   {
   4414     const location_t missing_close_brace_1_39
   4415       = linemap_position_for_line_and_column (line_table, ord_map, 1, 39);
   4416     const location_t matching_open_brace_1_18
   4417       = linemap_position_for_line_and_column (line_table, ord_map, 1, 18);
   4418     gcc_rich_location richloc (missing_close_brace_1_39);
   4419     bool added = richloc.add_location_if_nearby (matching_open_brace_1_18);
   4420     ASSERT_TRUE (added);
   4421     ASSERT_EQ (2, richloc.get_num_locations ());
   4422     test_diagnostic_context dc;
   4423     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4424     ASSERT_STREQ (" struct same_line { double x; double y; ;\n"
   4425 		  "                  ~                    ^\n",
   4426 		  pp_formatted_text (dc.printer));
   4427   }
   4428 
   4429   /* Test of add_location_if_nearby on a different line to the
   4430      primary location.  */
   4431   {
   4432     const location_t missing_close_brace_6_1
   4433       = linemap_position_for_line_and_column (line_table, ord_map, 6, 1);
   4434     const location_t matching_open_brace_3_1
   4435       = linemap_position_for_line_and_column (line_table, ord_map, 3, 1);
   4436     gcc_rich_location richloc (missing_close_brace_6_1);
   4437     bool added = richloc.add_location_if_nearby (matching_open_brace_3_1);
   4438     ASSERT_FALSE (added);
   4439     ASSERT_EQ (1, richloc.get_num_locations ());
   4440   }
   4441 }
   4442 
   4443 /* Verify that we print fixits even if they only affect lines
   4444    outside those covered by the ranges in the rich_location.  */
   4445 
   4446 static void
   4447 test_diagnostic_show_locus_fixit_lines (const line_table_case &case_)
   4448 {
   4449   /* Create a tempfile and write some text to it.
   4450      ...000000000111111111122222222223333333333.
   4451      ...123456789012345678901234567890123456789.  */
   4452   const char *content
   4453     = ("struct point { double x; double y; };\n" /* line 1.  */
   4454        "struct point origin = {x: 0.0,\n"        /* line 2.  */
   4455        "                       y\n"              /* line 3.  */
   4456        "\n"                                      /* line 4.  */
   4457        "\n"                                      /* line 5.  */
   4458        "                        : 0.0};\n");     /* line 6.  */
   4459   temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
   4460   line_table_test ltt (case_);
   4461 
   4462   const line_map_ordinary *ord_map
   4463     = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
   4464 					   tmp.get_filename (), 0));
   4465 
   4466   linemap_line_start (line_table, 1, 100);
   4467 
   4468   const location_t final_line_end
   4469     = linemap_position_for_line_and_column (line_table, ord_map, 6, 36);
   4470 
   4471   /* Don't attempt to run the tests if column data might be unavailable.  */
   4472   if (final_line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
   4473     return;
   4474 
   4475   /* A pair of tests for modernizing the initializers to C99-style.  */
   4476 
   4477   /* The one-liner case (line 2).  */
   4478   {
   4479     test_diagnostic_context dc;
   4480     const location_t x
   4481       = linemap_position_for_line_and_column (line_table, ord_map, 2, 24);
   4482     const location_t colon
   4483       = linemap_position_for_line_and_column (line_table, ord_map, 2, 25);
   4484     rich_location richloc (line_table, colon);
   4485     richloc.add_fixit_insert_before (x, ".");
   4486     richloc.add_fixit_replace (colon, "=");
   4487     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4488     ASSERT_STREQ (" struct point origin = {x: 0.0,\n"
   4489 		  "                         ^\n"
   4490 		  "                        .=\n",
   4491 		  pp_formatted_text (dc.printer));
   4492   }
   4493 
   4494   /* The multiline case.  The caret for the rich_location is on line 6;
   4495      verify that insertion fixit on line 3 is still printed (and that
   4496      span starts are printed due to the gap between the span at line 3
   4497      and that at line 6).  */
   4498   {
   4499     test_diagnostic_context dc;
   4500     const location_t y
   4501       = linemap_position_for_line_and_column (line_table, ord_map, 3, 24);
   4502     const location_t colon
   4503       = linemap_position_for_line_and_column (line_table, ord_map, 6, 25);
   4504     rich_location richloc (line_table, colon);
   4505     richloc.add_fixit_insert_before (y, ".");
   4506     richloc.add_fixit_replace (colon, "=");
   4507     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4508     ASSERT_STREQ ("FILENAME:3:24:\n"
   4509 		  "                        y\n"
   4510 		  "                        .\n"
   4511 		  "FILENAME:6:25:\n"
   4512 		  "                         : 0.0};\n"
   4513 		  "                         ^\n"
   4514 		  "                         =\n",
   4515 		  pp_formatted_text (dc.printer));
   4516   }
   4517 
   4518   /* As above, but verify the behavior of multiple line spans
   4519      with line-numbering enabled.  */
   4520   {
   4521     const location_t y
   4522       = linemap_position_for_line_and_column (line_table, ord_map, 3, 24);
   4523     const location_t colon
   4524       = linemap_position_for_line_and_column (line_table, ord_map, 6, 25);
   4525     rich_location richloc (line_table, colon);
   4526     richloc.add_fixit_insert_before (y, ".");
   4527     richloc.add_fixit_replace (colon, "=");
   4528     test_diagnostic_context dc;
   4529     dc.show_line_numbers_p = true;
   4530     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4531     ASSERT_STREQ ("    3 |                        y\n"
   4532 		  "      |                        .\n"
   4533 		  "......\n"
   4534 		  "    6 |                         : 0.0};\n"
   4535 		  "      |                         ^\n"
   4536 		  "      |                         =\n",
   4537 		  pp_formatted_text (dc.printer));
   4538   }
   4539 }
   4540 
   4541 
   4542 /* Verify that fix-it hints are appropriately consolidated.
   4543 
   4544    If any fix-it hints in a rich_location involve locations beyond
   4545    LINE_MAP_MAX_LOCATION_WITH_COLS, then we can't reliably apply
   4546    the fix-it as a whole, so there should be none.
   4547 
   4548    Otherwise, verify that consecutive "replace" and "remove" fix-its
   4549    are merged, and that other fix-its remain separate.   */
   4550 
   4551 static void
   4552 test_fixit_consolidation (const line_table_case &case_)
   4553 {
   4554   line_table_test ltt (case_);
   4555 
   4556   linemap_add (line_table, LC_ENTER, false, "test.c", 1);
   4557 
   4558   const location_t c10 = linemap_position_for_column (line_table, 10);
   4559   const location_t c15 = linemap_position_for_column (line_table, 15);
   4560   const location_t c16 = linemap_position_for_column (line_table, 16);
   4561   const location_t c17 = linemap_position_for_column (line_table, 17);
   4562   const location_t c20 = linemap_position_for_column (line_table, 20);
   4563   const location_t c21 = linemap_position_for_column (line_table, 21);
   4564   const location_t caret = c10;
   4565 
   4566   /* Insert + insert. */
   4567   {
   4568     rich_location richloc (line_table, caret);
   4569     richloc.add_fixit_insert_before (c10, "foo");
   4570     richloc.add_fixit_insert_before (c15, "bar");
   4571 
   4572     if (c15 > LINE_MAP_MAX_LOCATION_WITH_COLS)
   4573       /* Bogus column info for 2nd fixit, so no fixits.  */
   4574       ASSERT_EQ (0, richloc.get_num_fixit_hints ());
   4575     else
   4576       /* They should not have been merged.  */
   4577       ASSERT_EQ (2, richloc.get_num_fixit_hints ());
   4578   }
   4579 
   4580   /* Insert + replace. */
   4581   {
   4582     rich_location richloc (line_table, caret);
   4583     richloc.add_fixit_insert_before (c10, "foo");
   4584     richloc.add_fixit_replace (source_range::from_locations (c15, c17),
   4585 			       "bar");
   4586 
   4587     if (c17 > LINE_MAP_MAX_LOCATION_WITH_COLS)
   4588       /* Bogus column info for 2nd fixit, so no fixits.  */
   4589       ASSERT_EQ (0, richloc.get_num_fixit_hints ());
   4590     else
   4591       /* They should not have been merged.  */
   4592       ASSERT_EQ (2, richloc.get_num_fixit_hints ());
   4593   }
   4594 
   4595   /* Replace + non-consecutive insert. */
   4596   {
   4597     rich_location richloc (line_table, caret);
   4598     richloc.add_fixit_replace (source_range::from_locations (c10, c15),
   4599 			       "bar");
   4600     richloc.add_fixit_insert_before (c17, "foo");
   4601 
   4602     if (c17 > LINE_MAP_MAX_LOCATION_WITH_COLS)
   4603       /* Bogus column info for 2nd fixit, so no fixits.  */
   4604       ASSERT_EQ (0, richloc.get_num_fixit_hints ());
   4605     else
   4606       /* They should not have been merged.  */
   4607       ASSERT_EQ (2, richloc.get_num_fixit_hints ());
   4608   }
   4609 
   4610   /* Replace + non-consecutive replace. */
   4611   {
   4612     rich_location richloc (line_table, caret);
   4613     richloc.add_fixit_replace (source_range::from_locations (c10, c15),
   4614 			       "foo");
   4615     richloc.add_fixit_replace (source_range::from_locations (c17, c20),
   4616 			       "bar");
   4617 
   4618     if (c20 > LINE_MAP_MAX_LOCATION_WITH_COLS)
   4619       /* Bogus column info for 2nd fixit, so no fixits.  */
   4620       ASSERT_EQ (0, richloc.get_num_fixit_hints ());
   4621     else
   4622       /* They should not have been merged.  */
   4623       ASSERT_EQ (2, richloc.get_num_fixit_hints ());
   4624   }
   4625 
   4626   /* Replace + consecutive replace. */
   4627   {
   4628     rich_location richloc (line_table, caret);
   4629     richloc.add_fixit_replace (source_range::from_locations (c10, c15),
   4630 			       "foo");
   4631     richloc.add_fixit_replace (source_range::from_locations (c16, c20),
   4632 			       "bar");
   4633 
   4634     if (c20 > LINE_MAP_MAX_LOCATION_WITH_COLS)
   4635       /* Bogus column info for 2nd fixit, so no fixits.  */
   4636       ASSERT_EQ (0, richloc.get_num_fixit_hints ());
   4637     else
   4638       {
   4639 	/* They should have been merged into a single "replace".  */
   4640 	ASSERT_EQ (1, richloc.get_num_fixit_hints ());
   4641 	const fixit_hint *hint = richloc.get_fixit_hint (0);
   4642 	ASSERT_STREQ ("foobar", hint->get_string ());
   4643 	ASSERT_EQ (c10, hint->get_start_loc ());
   4644 	ASSERT_EQ (c21, hint->get_next_loc ());
   4645       }
   4646   }
   4647 
   4648   /* Replace + consecutive removal. */
   4649   {
   4650     rich_location richloc (line_table, caret);
   4651     richloc.add_fixit_replace (source_range::from_locations (c10, c15),
   4652 			       "foo");
   4653     richloc.add_fixit_remove (source_range::from_locations (c16, c20));
   4654 
   4655     if (c20 > LINE_MAP_MAX_LOCATION_WITH_COLS)
   4656       /* Bogus column info for 2nd fixit, so no fixits.  */
   4657       ASSERT_EQ (0, richloc.get_num_fixit_hints ());
   4658     else
   4659       {
   4660 	/* They should have been merged into a single replace, with the
   4661 	   range extended to cover that of the removal.  */
   4662 	ASSERT_EQ (1, richloc.get_num_fixit_hints ());
   4663 	const fixit_hint *hint = richloc.get_fixit_hint (0);
   4664 	ASSERT_STREQ ("foo", hint->get_string ());
   4665 	ASSERT_EQ (c10, hint->get_start_loc ());
   4666 	ASSERT_EQ (c21, hint->get_next_loc ());
   4667       }
   4668   }
   4669 
   4670   /* Consecutive removals. */
   4671   {
   4672     rich_location richloc (line_table, caret);
   4673     richloc.add_fixit_remove (source_range::from_locations (c10, c15));
   4674     richloc.add_fixit_remove (source_range::from_locations (c16, c20));
   4675 
   4676     if (c20 > LINE_MAP_MAX_LOCATION_WITH_COLS)
   4677       /* Bogus column info for 2nd fixit, so no fixits.  */
   4678       ASSERT_EQ (0, richloc.get_num_fixit_hints ());
   4679     else
   4680       {
   4681 	/* They should have been merged into a single "replace-with-empty".  */
   4682 	ASSERT_EQ (1, richloc.get_num_fixit_hints ());
   4683 	const fixit_hint *hint = richloc.get_fixit_hint (0);
   4684 	ASSERT_STREQ ("", hint->get_string ());
   4685 	ASSERT_EQ (c10, hint->get_start_loc ());
   4686 	ASSERT_EQ (c21, hint->get_next_loc ());
   4687       }
   4688   }
   4689 }
   4690 
   4691 /* Verify that the line_corrections machinery correctly prints
   4692    overlapping fixit-hints.  */
   4693 
   4694 static void
   4695 test_overlapped_fixit_printing (const line_table_case &case_)
   4696 {
   4697   /* Create a tempfile and write some text to it.
   4698      ...000000000111111111122222222223333333333.
   4699      ...123456789012345678901234567890123456789.  */
   4700   const char *content
   4701     = ("  foo *f = (foo *)ptr->field;\n");
   4702   temp_source_file tmp (SELFTEST_LOCATION, ".C", content);
   4703   line_table_test ltt (case_);
   4704 
   4705   const line_map_ordinary *ord_map
   4706     = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
   4707 					   tmp.get_filename (), 0));
   4708 
   4709   linemap_line_start (line_table, 1, 100);
   4710 
   4711   const location_t final_line_end
   4712     = linemap_position_for_line_and_column (line_table, ord_map, 6, 36);
   4713 
   4714   /* Don't attempt to run the tests if column data might be unavailable.  */
   4715   if (final_line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
   4716     return;
   4717 
   4718   /* A test for converting a C-style cast to a C++-style cast.  */
   4719   const location_t open_paren
   4720     = linemap_position_for_line_and_column (line_table, ord_map, 1, 12);
   4721   const location_t close_paren
   4722     = linemap_position_for_line_and_column (line_table, ord_map, 1, 18);
   4723   const location_t expr_start
   4724     = linemap_position_for_line_and_column (line_table, ord_map, 1, 19);
   4725   const location_t expr_finish
   4726     = linemap_position_for_line_and_column (line_table, ord_map, 1, 28);
   4727   const location_t expr = make_location (expr_start, expr_start, expr_finish);
   4728 
   4729   /* Various examples of fix-it hints that aren't themselves consolidated,
   4730      but for which the *printing* may need consolidation.  */
   4731 
   4732   /* Example where 3 fix-it hints are printed as one.  */
   4733   {
   4734     test_diagnostic_context dc;
   4735     rich_location richloc (line_table, expr);
   4736     richloc.add_fixit_replace (open_paren, "const_cast<");
   4737     richloc.add_fixit_replace (close_paren, "> (");
   4738     richloc.add_fixit_insert_after (")");
   4739 
   4740     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4741     ASSERT_STREQ ("   foo *f = (foo *)ptr->field;\n"
   4742 		  "                   ^~~~~~~~~~\n"
   4743 		  "            -----------------\n"
   4744 		  "            const_cast<foo *> (ptr->field)\n",
   4745 		  pp_formatted_text (dc.printer));
   4746 
   4747     /* Unit-test the line_corrections machinery.  */
   4748     char_display_policy policy (make_policy (dc, richloc));
   4749     ASSERT_EQ (3, richloc.get_num_fixit_hints ());
   4750     const fixit_hint *hint_0 = richloc.get_fixit_hint (0);
   4751     ASSERT_EQ (column_range (12, 12),
   4752 	       get_affected_range (policy, hint_0, CU_BYTES));
   4753     ASSERT_EQ (column_range (12, 12),
   4754 	       get_affected_range (policy, hint_0, CU_DISPLAY_COLS));
   4755     ASSERT_EQ (column_range (12, 22), get_printed_columns (policy, hint_0));
   4756     const fixit_hint *hint_1 = richloc.get_fixit_hint (1);
   4757     ASSERT_EQ (column_range (18, 18),
   4758 	       get_affected_range (policy, hint_1, CU_BYTES));
   4759     ASSERT_EQ (column_range (18, 18),
   4760 	       get_affected_range (policy, hint_1, CU_DISPLAY_COLS));
   4761     ASSERT_EQ (column_range (18, 20), get_printed_columns (policy, hint_1));
   4762     const fixit_hint *hint_2 = richloc.get_fixit_hint (2);
   4763     ASSERT_EQ (column_range (29, 28),
   4764 	       get_affected_range (policy, hint_2, CU_BYTES));
   4765     ASSERT_EQ (column_range (29, 28),
   4766 	       get_affected_range (policy, hint_2, CU_DISPLAY_COLS));
   4767     ASSERT_EQ (column_range (29, 29), get_printed_columns (policy, hint_2));
   4768 
   4769     /* Add each hint in turn to a line_corrections instance,
   4770        and verify that they are consolidated into one correction instance
   4771        as expected.  */
   4772     line_corrections lc (policy, tmp.get_filename (), 1);
   4773 
   4774     /* The first replace hint by itself.  */
   4775     lc.add_hint (hint_0);
   4776     ASSERT_EQ (1, lc.m_corrections.length ());
   4777     ASSERT_EQ (column_range (12, 12), lc.m_corrections[0]->m_affected_bytes);
   4778     ASSERT_EQ (column_range (12, 12), lc.m_corrections[0]->m_affected_columns);
   4779     ASSERT_EQ (column_range (12, 22), lc.m_corrections[0]->m_printed_columns);
   4780     ASSERT_STREQ ("const_cast<", lc.m_corrections[0]->m_text);
   4781 
   4782     /* After the second replacement hint, they are printed together
   4783        as a replacement (along with the text between them).  */
   4784     lc.add_hint (hint_1);
   4785     ASSERT_EQ (1, lc.m_corrections.length ());
   4786     ASSERT_STREQ ("const_cast<foo *> (", lc.m_corrections[0]->m_text);
   4787     ASSERT_EQ (column_range (12, 18), lc.m_corrections[0]->m_affected_bytes);
   4788     ASSERT_EQ (column_range (12, 18), lc.m_corrections[0]->m_affected_columns);
   4789     ASSERT_EQ (column_range (12, 30), lc.m_corrections[0]->m_printed_columns);
   4790 
   4791     /* After the final insertion hint, they are all printed together
   4792        as a replacement (along with the text between them).  */
   4793     lc.add_hint (hint_2);
   4794     ASSERT_STREQ ("const_cast<foo *> (ptr->field)",
   4795 		  lc.m_corrections[0]->m_text);
   4796     ASSERT_EQ (1, lc.m_corrections.length ());
   4797     ASSERT_EQ (column_range (12, 28), lc.m_corrections[0]->m_affected_bytes);
   4798     ASSERT_EQ (column_range (12, 28), lc.m_corrections[0]->m_affected_columns);
   4799     ASSERT_EQ (column_range (12, 41), lc.m_corrections[0]->m_printed_columns);
   4800   }
   4801 
   4802   /* Example where two are consolidated during printing.  */
   4803   {
   4804     test_diagnostic_context dc;
   4805     rich_location richloc (line_table, expr);
   4806     richloc.add_fixit_replace (open_paren, "CAST (");
   4807     richloc.add_fixit_replace (close_paren, ") (");
   4808     richloc.add_fixit_insert_after (")");
   4809 
   4810     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4811     ASSERT_STREQ ("   foo *f = (foo *)ptr->field;\n"
   4812 		  "                   ^~~~~~~~~~\n"
   4813 		  "            -\n"
   4814 		  "            CAST (-\n"
   4815 		  "                  ) (        )\n",
   4816 		  pp_formatted_text (dc.printer));
   4817   }
   4818 
   4819   /* Example where none are consolidated during printing.  */
   4820   {
   4821     test_diagnostic_context dc;
   4822     rich_location richloc (line_table, expr);
   4823     richloc.add_fixit_replace (open_paren, "CST (");
   4824     richloc.add_fixit_replace (close_paren, ") (");
   4825     richloc.add_fixit_insert_after (")");
   4826 
   4827     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4828     ASSERT_STREQ ("   foo *f = (foo *)ptr->field;\n"
   4829 		  "                   ^~~~~~~~~~\n"
   4830 		  "            -\n"
   4831 		  "            CST ( -\n"
   4832 		  "                  ) (        )\n",
   4833 		  pp_formatted_text (dc.printer));
   4834   }
   4835 
   4836   /* Example of deletion fix-it hints.  */
   4837   {
   4838     test_diagnostic_context dc;
   4839     rich_location richloc (line_table, expr);
   4840     richloc.add_fixit_insert_before (open_paren, "(bar *)");
   4841     source_range victim = {open_paren, close_paren};
   4842     richloc.add_fixit_remove (victim);
   4843 
   4844     /* This case is actually handled by fixit-consolidation,
   4845        rather than by line_corrections.  */
   4846     ASSERT_EQ (1, richloc.get_num_fixit_hints ());
   4847 
   4848     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4849     ASSERT_STREQ ("   foo *f = (foo *)ptr->field;\n"
   4850 		  "                   ^~~~~~~~~~\n"
   4851 		  "            -------\n"
   4852 		  "            (bar *)\n",
   4853 		  pp_formatted_text (dc.printer));
   4854   }
   4855 
   4856   /* Example of deletion fix-it hints that would overlap.  */
   4857   {
   4858     test_diagnostic_context dc;
   4859     rich_location richloc (line_table, expr);
   4860     richloc.add_fixit_insert_before (open_paren, "(longer *)");
   4861     source_range victim = {expr_start, expr_finish};
   4862     richloc.add_fixit_remove (victim);
   4863 
   4864     /* These fixits are not consolidated.  */
   4865     ASSERT_EQ (2, richloc.get_num_fixit_hints ());
   4866 
   4867     /* But the corrections are.  */
   4868     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4869     ASSERT_STREQ ("   foo *f = (foo *)ptr->field;\n"
   4870 		  "                   ^~~~~~~~~~\n"
   4871 		  "            -----------------\n"
   4872 		  "            (longer *)(foo *)\n",
   4873 		  pp_formatted_text (dc.printer));
   4874   }
   4875 
   4876   /* Example of insertion fix-it hints that would overlap.  */
   4877   {
   4878     test_diagnostic_context dc;
   4879     rich_location richloc (line_table, expr);
   4880     richloc.add_fixit_insert_before (open_paren, "LONGER THAN THE CAST");
   4881     richloc.add_fixit_insert_after (close_paren, "TEST");
   4882 
   4883     /* The first insertion is long enough that if printed naively,
   4884        it would overlap with the second.
   4885        Verify that they are printed as a single replacement.  */
   4886     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4887     ASSERT_STREQ ("   foo *f = (foo *)ptr->field;\n"
   4888 		  "                   ^~~~~~~~~~\n"
   4889 		  "            -------\n"
   4890 		  "            LONGER THAN THE CAST(foo *)TEST\n",
   4891 		  pp_formatted_text (dc.printer));
   4892   }
   4893 }
   4894 
   4895 /* Multibyte-aware version of preceding tests.  See comments above
   4896    test_one_liner_simple_caret_utf8() too, we use the same two multibyte
   4897    characters here.  */
   4898 
   4899 static void
   4900 test_overlapped_fixit_printing_utf8 (const line_table_case &case_)
   4901 {
   4902   /* Create a tempfile and write some text to it.  */
   4903 
   4904   const char *content
   4905     /* Display columns.
   4906        00000000000000000000000111111111111111111111111222222222222222223
   4907        12344444444555555556789012344444444555555556789012345678999999990  */
   4908     = "  f\xf0\x9f\x98\x82 *f = (f\xf0\x9f\x98\x82 *)ptr->field\xcf\x80;\n";
   4909     /* 00000000000000000000011111111111111111111112222222222333333333333
   4910        12344445555666677778901234566667777888899990123456789012333344445
   4911        Byte columns.  */
   4912 
   4913   temp_source_file tmp (SELFTEST_LOCATION, ".C", content);
   4914   line_table_test ltt (case_);
   4915 
   4916   const line_map_ordinary *ord_map
   4917     = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
   4918 					   tmp.get_filename (), 0));
   4919 
   4920   linemap_line_start (line_table, 1, 100);
   4921 
   4922   const location_t final_line_end
   4923     = linemap_position_for_line_and_column (line_table, ord_map, 6, 50);
   4924 
   4925   /* Don't attempt to run the tests if column data might be unavailable.  */
   4926   if (final_line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
   4927     return;
   4928 
   4929   /* A test for converting a C-style cast to a C++-style cast.  */
   4930   const location_t open_paren
   4931     = linemap_position_for_line_and_column (line_table, ord_map, 1, 14);
   4932   const location_t close_paren
   4933     = linemap_position_for_line_and_column (line_table, ord_map, 1, 22);
   4934   const location_t expr_start
   4935     = linemap_position_for_line_and_column (line_table, ord_map, 1, 23);
   4936   const location_t expr_finish
   4937     = linemap_position_for_line_and_column (line_table, ord_map, 1, 34);
   4938   const location_t expr = make_location (expr_start, expr_start, expr_finish);
   4939 
   4940   /* Various examples of fix-it hints that aren't themselves consolidated,
   4941      but for which the *printing* may need consolidation.  */
   4942 
   4943   /* Example where 3 fix-it hints are printed as one.  */
   4944   {
   4945     test_diagnostic_context dc;
   4946     rich_location richloc (line_table, expr);
   4947     richloc.add_fixit_replace (open_paren, "const_cast<");
   4948     richloc.add_fixit_replace (close_paren, "> (");
   4949     richloc.add_fixit_insert_after (")");
   4950 
   4951     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   4952     ASSERT_STREQ ("   f\xf0\x9f\x98\x82"
   4953 			" *f = (f\xf0\x9f\x98\x82"
   4954 				  " *)ptr->field\xcf\x80"
   4955 						";\n"
   4956 		  "                   ^~~~~~~~~~~\n"
   4957 		  "            ------------------\n"
   4958 		  "            const_cast<f\xf0\x9f\x98\x82"
   4959 					    " *> (ptr->field\xcf\x80"
   4960 							    ")\n",
   4961 		  pp_formatted_text (dc.printer));
   4962 
   4963     /* Unit-test the line_corrections machinery.  */
   4964     char_display_policy policy (make_policy (dc, richloc));
   4965     ASSERT_EQ (3, richloc.get_num_fixit_hints ());
   4966     const fixit_hint *hint_0 = richloc.get_fixit_hint (0);
   4967     ASSERT_EQ (column_range (14, 14),
   4968 	       get_affected_range (policy, hint_0, CU_BYTES));
   4969     ASSERT_EQ (column_range (12, 12),
   4970 	       get_affected_range (policy, hint_0, CU_DISPLAY_COLS));
   4971     ASSERT_EQ (column_range (12, 22), get_printed_columns (policy, hint_0));
   4972     const fixit_hint *hint_1 = richloc.get_fixit_hint (1);
   4973     ASSERT_EQ (column_range (22, 22),
   4974 	       get_affected_range (policy, hint_1, CU_BYTES));
   4975     ASSERT_EQ (column_range (18, 18),
   4976 	       get_affected_range (policy, hint_1, CU_DISPLAY_COLS));
   4977     ASSERT_EQ (column_range (18, 20), get_printed_columns (policy, hint_1));
   4978     const fixit_hint *hint_2 = richloc.get_fixit_hint (2);
   4979     ASSERT_EQ (column_range (35, 34),
   4980 	       get_affected_range (policy, hint_2, CU_BYTES));
   4981     ASSERT_EQ (column_range (30, 29),
   4982 	       get_affected_range (policy, hint_2, CU_DISPLAY_COLS));
   4983     ASSERT_EQ (column_range (30, 30), get_printed_columns (policy, hint_2));
   4984 
   4985     /* Add each hint in turn to a line_corrections instance,
   4986        and verify that they are consolidated into one correction instance
   4987        as expected.  */
   4988     line_corrections lc (policy, tmp.get_filename (), 1);
   4989 
   4990     /* The first replace hint by itself.  */
   4991     lc.add_hint (hint_0);
   4992     ASSERT_EQ (1, lc.m_corrections.length ());
   4993     ASSERT_EQ (column_range (14, 14), lc.m_corrections[0]->m_affected_bytes);
   4994     ASSERT_EQ (column_range (12, 12), lc.m_corrections[0]->m_affected_columns);
   4995     ASSERT_EQ (column_range (12, 22), lc.m_corrections[0]->m_printed_columns);
   4996     ASSERT_STREQ ("const_cast<", lc.m_corrections[0]->m_text);
   4997 
   4998     /* After the second replacement hint, they are printed together
   4999        as a replacement (along with the text between them).  */
   5000     lc.add_hint (hint_1);
   5001     ASSERT_EQ (1, lc.m_corrections.length ());
   5002     ASSERT_STREQ ("const_cast<f\xf0\x9f\x98\x82 *> (",
   5003 		  lc.m_corrections[0]->m_text);
   5004     ASSERT_EQ (column_range (14, 22), lc.m_corrections[0]->m_affected_bytes);
   5005     ASSERT_EQ (column_range (12, 18), lc.m_corrections[0]->m_affected_columns);
   5006     ASSERT_EQ (column_range (12, 30), lc.m_corrections[0]->m_printed_columns);
   5007 
   5008     /* After the final insertion hint, they are all printed together
   5009        as a replacement (along with the text between them).  */
   5010     lc.add_hint (hint_2);
   5011     ASSERT_STREQ ("const_cast<f\xf0\x9f\x98\x82 *> (ptr->field\xcf\x80)",
   5012 		  lc.m_corrections[0]->m_text);
   5013     ASSERT_EQ (1, lc.m_corrections.length ());
   5014     ASSERT_EQ (column_range (14, 34), lc.m_corrections[0]->m_affected_bytes);
   5015     ASSERT_EQ (column_range (12, 29), lc.m_corrections[0]->m_affected_columns);
   5016     ASSERT_EQ (column_range (12, 42), lc.m_corrections[0]->m_printed_columns);
   5017   }
   5018 
   5019   /* Example where two are consolidated during printing.  */
   5020   {
   5021     test_diagnostic_context dc;
   5022     rich_location richloc (line_table, expr);
   5023     richloc.add_fixit_replace (open_paren, "CAST (");
   5024     richloc.add_fixit_replace (close_paren, ") (");
   5025     richloc.add_fixit_insert_after (")");
   5026 
   5027     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5028     ASSERT_STREQ ("   f\xf0\x9f\x98\x82"
   5029 			" *f = (f\xf0\x9f\x98\x82"
   5030 				  " *)ptr->field\xcf\x80"
   5031 						";\n"
   5032 		  "                   ^~~~~~~~~~~\n"
   5033 		  "            -\n"
   5034 		  "            CAST (-\n"
   5035 		  "                  ) (         )\n",
   5036 		  pp_formatted_text (dc.printer));
   5037   }
   5038 
   5039   /* Example where none are consolidated during printing.  */
   5040   {
   5041     test_diagnostic_context dc;
   5042     rich_location richloc (line_table, expr);
   5043     richloc.add_fixit_replace (open_paren, "CST (");
   5044     richloc.add_fixit_replace (close_paren, ") (");
   5045     richloc.add_fixit_insert_after (")");
   5046 
   5047     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5048     ASSERT_STREQ ("   f\xf0\x9f\x98\x82"
   5049 			" *f = (f\xf0\x9f\x98\x82"
   5050 				  " *)ptr->field\xcf\x80"
   5051 						";\n"
   5052 		  "                   ^~~~~~~~~~~\n"
   5053 		  "            -\n"
   5054 		  "            CST ( -\n"
   5055 		  "                  ) (         )\n",
   5056 		  pp_formatted_text (dc.printer));
   5057   }
   5058 
   5059   /* Example of deletion fix-it hints.  */
   5060   {
   5061     test_diagnostic_context dc;
   5062     rich_location richloc (line_table, expr);
   5063     richloc.add_fixit_insert_before (open_paren, "(bar\xf0\x9f\x98\x82 *)");
   5064     source_range victim = {open_paren, close_paren};
   5065     richloc.add_fixit_remove (victim);
   5066 
   5067     /* This case is actually handled by fixit-consolidation,
   5068        rather than by line_corrections.  */
   5069     ASSERT_EQ (1, richloc.get_num_fixit_hints ());
   5070 
   5071     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5072     ASSERT_STREQ ("   f\xf0\x9f\x98\x82"
   5073 			" *f = (f\xf0\x9f\x98\x82"
   5074 				  " *)ptr->field\xcf\x80"
   5075 						";\n"
   5076 		  "                   ^~~~~~~~~~~\n"
   5077 		  "            -------\n"
   5078 		  "            (bar\xf0\x9f\x98\x82"
   5079 				    " *)\n",
   5080 		  pp_formatted_text (dc.printer));
   5081   }
   5082 
   5083   /* Example of deletion fix-it hints that would overlap.  */
   5084   {
   5085     test_diagnostic_context dc;
   5086     rich_location richloc (line_table, expr);
   5087     richloc.add_fixit_insert_before (open_paren, "(long\xf0\x9f\x98\x82 *)");
   5088     source_range victim = {expr_start, expr_finish};
   5089     richloc.add_fixit_remove (victim);
   5090 
   5091     /* These fixits are not consolidated.  */
   5092     ASSERT_EQ (2, richloc.get_num_fixit_hints ());
   5093 
   5094     /* But the corrections are.  */
   5095     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5096     ASSERT_STREQ ("   f\xf0\x9f\x98\x82"
   5097 			" *f = (f\xf0\x9f\x98\x82"
   5098 				  " *)ptr->field\xcf\x80"
   5099 						";\n"
   5100 		  "                   ^~~~~~~~~~~\n"
   5101 		  "            ------------------\n"
   5102 		  "            (long\xf0\x9f\x98\x82"
   5103 				     " *)(f\xf0\x9f\x98\x82"
   5104 					    " *)\n",
   5105 		  pp_formatted_text (dc.printer));
   5106   }
   5107 
   5108   /* Example of insertion fix-it hints that would overlap.  */
   5109   {
   5110     test_diagnostic_context dc;
   5111     rich_location richloc (line_table, expr);
   5112     richloc.add_fixit_insert_before
   5113       (open_paren, "L\xf0\x9f\x98\x82NGER THAN THE CAST");
   5114     richloc.add_fixit_insert_after (close_paren, "TEST");
   5115 
   5116     /* The first insertion is long enough that if printed naively,
   5117        it would overlap with the second.
   5118        Verify that they are printed as a single replacement.  */
   5119     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5120     ASSERT_STREQ ("   f\xf0\x9f\x98\x82"
   5121 			" *f = (f\xf0\x9f\x98\x82"
   5122 				  " *)ptr->field\xcf\x80"
   5123 						";\n"
   5124 		  "                   ^~~~~~~~~~~\n"
   5125 		  "            -------\n"
   5126 		  "            L\xf0\x9f\x98\x82"
   5127 				 "NGER THAN THE CAST(f\xf0\x9f\x98\x82"
   5128 						       " *)TEST\n",
   5129 		  pp_formatted_text (dc.printer));
   5130   }
   5131 }
   5132 
   5133 /* Verify that the line_corrections machinery correctly prints
   5134    overlapping fixit-hints that have been added in the wrong
   5135    order.
   5136    Adapted from PR c/81405 seen on gcc.dg/init-excess-1.c*/
   5137 
   5138 static void
   5139 test_overlapped_fixit_printing_2 (const line_table_case &case_)
   5140 {
   5141   /* Create a tempfile and write some text to it.
   5142      ...000000000111111111122222222223333333333.
   5143      ...123456789012345678901234567890123456789.  */
   5144   const char *content
   5145     = ("int a5[][0][0] = { 1, 2 };\n");
   5146   temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
   5147   line_table_test ltt (case_);
   5148 
   5149   const line_map_ordinary *ord_map
   5150     = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
   5151 					   tmp.get_filename (), 0));
   5152 
   5153   linemap_line_start (line_table, 1, 100);
   5154 
   5155   const location_t final_line_end
   5156     = linemap_position_for_line_and_column (line_table, ord_map, 1, 100);
   5157 
   5158   /* Don't attempt to run the tests if column data might be unavailable.  */
   5159   if (final_line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
   5160     return;
   5161 
   5162   const location_t col_1
   5163     = linemap_position_for_line_and_column (line_table, ord_map, 1, 1);
   5164   const location_t col_20
   5165     = linemap_position_for_line_and_column (line_table, ord_map, 1, 20);
   5166   const location_t col_21
   5167     = linemap_position_for_line_and_column (line_table, ord_map, 1, 21);
   5168   const location_t col_23
   5169     = linemap_position_for_line_and_column (line_table, ord_map, 1, 23);
   5170   const location_t col_25
   5171     = linemap_position_for_line_and_column (line_table, ord_map, 1, 25);
   5172 
   5173   /* Two insertions, in the wrong order.  */
   5174   {
   5175     test_diagnostic_context dc;
   5176 
   5177     rich_location richloc (line_table, col_20);
   5178     richloc.add_fixit_insert_before (col_23, "{");
   5179     richloc.add_fixit_insert_before (col_21, "}");
   5180 
   5181     /* These fixits should be accepted; they can't be consolidated.  */
   5182     char_display_policy policy (make_policy (dc, richloc));
   5183     ASSERT_EQ (2, richloc.get_num_fixit_hints ());
   5184     const fixit_hint *hint_0 = richloc.get_fixit_hint (0);
   5185     ASSERT_EQ (column_range (23, 22),
   5186 	       get_affected_range (policy, hint_0, CU_BYTES));
   5187     ASSERT_EQ (column_range (23, 23), get_printed_columns (policy, hint_0));
   5188     const fixit_hint *hint_1 = richloc.get_fixit_hint (1);
   5189     ASSERT_EQ (column_range (21, 20),
   5190 	       get_affected_range (policy, hint_1, CU_BYTES));
   5191     ASSERT_EQ (column_range (21, 21), get_printed_columns (policy, hint_1));
   5192 
   5193     /* Verify that they're printed correctly.  */
   5194     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5195     ASSERT_STREQ (" int a5[][0][0] = { 1, 2 };\n"
   5196 		  "                    ^\n"
   5197 		  "                     } {\n",
   5198 		  pp_formatted_text (dc.printer));
   5199   }
   5200 
   5201   /* Various overlapping insertions, some occurring "out of order"
   5202      (reproducing the fix-it hints from PR c/81405).  */
   5203   {
   5204     test_diagnostic_context dc;
   5205     rich_location richloc (line_table, col_20);
   5206 
   5207     richloc.add_fixit_insert_before (col_20, "{{");
   5208     richloc.add_fixit_insert_before (col_21, "}}");
   5209     richloc.add_fixit_insert_before (col_23, "{");
   5210     richloc.add_fixit_insert_before (col_21, "}");
   5211     richloc.add_fixit_insert_before (col_23, "{{");
   5212     richloc.add_fixit_insert_before (col_25, "}");
   5213     richloc.add_fixit_insert_before (col_21, "}");
   5214     richloc.add_fixit_insert_before (col_1, "{");
   5215     richloc.add_fixit_insert_before (col_25, "}");
   5216     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5217     ASSERT_STREQ (" int a5[][0][0] = { 1, 2 };\n"
   5218 		  "                    ^\n"
   5219 		  " {                  -----\n"
   5220 		  "                    {{1}}}}, {{{2 }}\n",
   5221 		  pp_formatted_text (dc.printer));
   5222   }
   5223 }
   5224 
   5225 /* Insertion fix-it hint: adding a "break;" on a line by itself.  */
   5226 
   5227 static void
   5228 test_fixit_insert_containing_newline (const line_table_case &case_)
   5229 {
   5230   /* Create a tempfile and write some text to it.
   5231      .........................0000000001111111.
   5232      .........................1234567890123456.  */
   5233   const char *old_content = ("    case 'a':\n" /* line 1. */
   5234 			     "      x = a;\n"  /* line 2. */
   5235 			     "    case 'b':\n" /* line 3. */
   5236 			     "      x = b;\n");/* line 4. */
   5237 
   5238   temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
   5239   line_table_test ltt (case_);
   5240   linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 3);
   5241 
   5242   location_t case_start = linemap_position_for_column (line_table, 5);
   5243   location_t case_finish = linemap_position_for_column (line_table, 13);
   5244   location_t case_loc = make_location (case_start, case_start, case_finish);
   5245   location_t line_start = linemap_position_for_column (line_table, 1);
   5246 
   5247   if (case_finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
   5248     return;
   5249 
   5250   /* Add a "break;" on a line by itself before line 3 i.e. before
   5251      column 1 of line 3. */
   5252   {
   5253     rich_location richloc (line_table, case_loc);
   5254     richloc.add_fixit_insert_before (line_start, "      break;\n");
   5255 
   5256     /* Without line numbers.  */
   5257     {
   5258       test_diagnostic_context dc;
   5259       diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5260       ASSERT_STREQ ("       x = a;\n"
   5261 		    "+      break;\n"
   5262 		    "     case 'b':\n"
   5263 		    "     ^~~~~~~~~\n",
   5264 		    pp_formatted_text (dc.printer));
   5265     }
   5266 
   5267     /* With line numbers.  */
   5268     {
   5269       test_diagnostic_context dc;
   5270       dc.show_line_numbers_p = true;
   5271       diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5272       ASSERT_STREQ ("    2 |       x = a;\n"
   5273 		    "  +++ |+      break;\n"
   5274 		    "    3 |     case 'b':\n"
   5275 		    "      |     ^~~~~~~~~\n",
   5276 		    pp_formatted_text (dc.printer));
   5277     }
   5278   }
   5279 
   5280   /* Verify that attempts to add text with a newline fail when the
   5281      insertion point is *not* at the start of a line.  */
   5282   {
   5283     rich_location richloc (line_table, case_loc);
   5284     richloc.add_fixit_insert_before (case_start, "break;\n");
   5285     ASSERT_TRUE (richloc.seen_impossible_fixit_p ());
   5286     test_diagnostic_context dc;
   5287     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5288     ASSERT_STREQ ("     case 'b':\n"
   5289 		  "     ^~~~~~~~~\n",
   5290 		  pp_formatted_text (dc.printer));
   5291   }
   5292 }
   5293 
   5294 /* Insertion fix-it hint: adding a "#include <stdio.h>\n" to the top
   5295    of the file, where the fix-it is printed in a different line-span
   5296    to the primary range of the diagnostic.  */
   5297 
   5298 static void
   5299 test_fixit_insert_containing_newline_2 (const line_table_case &case_)
   5300 {
   5301   /* Create a tempfile and write some text to it.
   5302      .........................0000000001111111.
   5303      .........................1234567890123456.  */
   5304   const char *old_content = ("test (int ch)\n"  /* line 1. */
   5305 			     "{\n"              /* line 2. */
   5306 			     " putchar (ch);\n" /* line 3. */
   5307 			     "}\n");            /* line 4. */
   5308 
   5309   temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
   5310   line_table_test ltt (case_);
   5311 
   5312   const line_map_ordinary *ord_map = linemap_check_ordinary
   5313     (linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0));
   5314   linemap_line_start (line_table, 1, 100);
   5315 
   5316   /* The primary range is the "putchar" token.  */
   5317   location_t putchar_start
   5318     = linemap_position_for_line_and_column (line_table, ord_map, 3, 2);
   5319   location_t putchar_finish
   5320     = linemap_position_for_line_and_column (line_table, ord_map, 3, 8);
   5321   location_t putchar_loc
   5322     = make_location (putchar_start, putchar_start, putchar_finish);
   5323   rich_location richloc (line_table, putchar_loc);
   5324 
   5325   /* Add a "#include <stdio.h>" on a line by itself at the top of the file.  */
   5326   location_t file_start
   5327      = linemap_position_for_line_and_column (line_table, ord_map,  1, 1);
   5328   richloc.add_fixit_insert_before (file_start, "#include <stdio.h>\n");
   5329 
   5330   if (putchar_finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
   5331     return;
   5332 
   5333   {
   5334     test_diagnostic_context dc;
   5335     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5336     ASSERT_STREQ ("FILENAME:1:1:\n"
   5337 		  "+#include <stdio.h>\n"
   5338 		  " test (int ch)\n"
   5339 		  "FILENAME:3:2:\n"
   5340 		  "  putchar (ch);\n"
   5341 		  "  ^~~~~~~\n",
   5342 		  pp_formatted_text (dc.printer));
   5343   }
   5344 
   5345   /* With line-numbering, the line spans are close enough to be
   5346      consolidated, since it makes little sense to skip line 2.  */
   5347   {
   5348     test_diagnostic_context dc;
   5349     dc.show_line_numbers_p = true;
   5350     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5351     ASSERT_STREQ ("  +++ |+#include <stdio.h>\n"
   5352 		  "    1 | test (int ch)\n"
   5353 		  "    2 | {\n"
   5354 		  "    3 |  putchar (ch);\n"
   5355 		  "      |  ^~~~~~~\n",
   5356 		  pp_formatted_text (dc.printer));
   5357   }
   5358 }
   5359 
   5360 /* Replacement fix-it hint containing a newline.
   5361    This will fail, as newlines are only supported when inserting at the
   5362    beginning of a line.  */
   5363 
   5364 static void
   5365 test_fixit_replace_containing_newline (const line_table_case &case_)
   5366 {
   5367   /* Create a tempfile and write some text to it.
   5368     .........................0000000001111.
   5369     .........................1234567890123.  */
   5370   const char *old_content = "foo = bar ();\n";
   5371 
   5372   temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
   5373   line_table_test ltt (case_);
   5374   linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
   5375 
   5376   /* Replace the " = " with "\n  = ", as if we were reformatting an
   5377      overly long line.  */
   5378   location_t start = linemap_position_for_column (line_table, 4);
   5379   location_t finish = linemap_position_for_column (line_table, 6);
   5380   location_t loc = linemap_position_for_column (line_table, 13);
   5381   rich_location richloc (line_table, loc);
   5382   source_range range = source_range::from_locations (start, finish);
   5383   richloc.add_fixit_replace (range, "\n =");
   5384 
   5385   /* Arbitrary newlines are not yet supported within fix-it hints, so
   5386      the fix-it should not be displayed.  */
   5387   ASSERT_TRUE (richloc.seen_impossible_fixit_p ());
   5388 
   5389   if (finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
   5390     return;
   5391 
   5392   test_diagnostic_context dc;
   5393   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5394   ASSERT_STREQ (" foo = bar ();\n"
   5395 		"             ^\n",
   5396 		pp_formatted_text (dc.printer));
   5397 }
   5398 
   5399 /* Fix-it hint, attempting to delete a newline.
   5400    This will fail, as we currently only support fix-it hints that
   5401    affect one line at a time.  */
   5402 
   5403 static void
   5404 test_fixit_deletion_affecting_newline (const line_table_case &case_)
   5405 {
   5406   /* Create a tempfile and write some text to it.
   5407     ..........................0000000001111.
   5408     ..........................1234567890123.  */
   5409   const char *old_content = ("foo = bar (\n"
   5410 			     "      );\n");
   5411 
   5412   temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
   5413   line_table_test ltt (case_);
   5414   const line_map_ordinary *ord_map = linemap_check_ordinary
   5415     (linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0));
   5416   linemap_line_start (line_table, 1, 100);
   5417 
   5418   /* Attempt to delete the " (\n...)".  */
   5419   location_t start
   5420     = linemap_position_for_line_and_column (line_table, ord_map, 1, 10);
   5421   location_t caret
   5422     = linemap_position_for_line_and_column (line_table, ord_map, 1, 11);
   5423   location_t finish
   5424     = linemap_position_for_line_and_column (line_table, ord_map, 2, 7);
   5425   location_t loc = make_location (caret, start, finish);
   5426   rich_location richloc (line_table, loc);
   5427   richloc. add_fixit_remove ();
   5428 
   5429   /* Fix-it hints that affect more than one line are not yet supported, so
   5430      the fix-it should not be displayed.  */
   5431   ASSERT_TRUE (richloc.seen_impossible_fixit_p ());
   5432 
   5433   if (finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
   5434     return;
   5435 
   5436   test_diagnostic_context dc;
   5437   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5438   ASSERT_STREQ (" foo = bar (\n"
   5439 		"          ~^\n"
   5440 		"       );\n"
   5441 		"       ~    \n",
   5442 		pp_formatted_text (dc.printer));
   5443 }
   5444 
   5445 static void
   5446 test_tab_expansion (const line_table_case &case_)
   5447 {
   5448   /* Create a tempfile and write some text to it.  This example uses a tabstop
   5449      of 8, as the column numbers attempt to indicate:
   5450 
   5451     .....................000.01111111111.22222333333  display
   5452     .....................123.90123456789.56789012345  columns  */
   5453   const char *content = "  \t   This: `\t' is a tab.\n";
   5454   /* ....................000 00000011111 11111222222  byte
   5455      ....................123 45678901234 56789012345  columns  */
   5456 
   5457   const int tabstop = 8;
   5458   cpp_char_column_policy policy (tabstop, cpp_wcwidth);
   5459   const int first_non_ws_byte_col = 7;
   5460   const int right_quote_byte_col = 15;
   5461   const int last_byte_col = 25;
   5462   ASSERT_EQ (35, cpp_display_width (content, last_byte_col, policy));
   5463 
   5464   temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
   5465   line_table_test ltt (case_);
   5466   linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
   5467 
   5468   /* Don't attempt to run the tests if column data might be unavailable.  */
   5469   location_t line_end = linemap_position_for_column (line_table, last_byte_col);
   5470   if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
   5471     return;
   5472 
   5473   /* Check that the leading whitespace with mixed tabs and spaces is expanded
   5474      into 11 spaces.  Recall that print_line() also puts one space before
   5475      everything too.  */
   5476   {
   5477     test_diagnostic_context dc;
   5478     dc.tabstop = tabstop;
   5479     rich_location richloc (line_table,
   5480 			   linemap_position_for_column (line_table,
   5481 							first_non_ws_byte_col));
   5482     layout test_layout (&dc, &richloc, DK_ERROR);
   5483     test_layout.print_line (1);
   5484     ASSERT_STREQ ("            This: `      ' is a tab.\n"
   5485 		  "            ^\n",
   5486 		  pp_formatted_text (dc.printer));
   5487   }
   5488 
   5489   /* Confirm the display width was tracked correctly across the internal tab
   5490      as well.  */
   5491   {
   5492     test_diagnostic_context dc;
   5493     dc.tabstop = tabstop;
   5494     rich_location richloc (line_table,
   5495 			   linemap_position_for_column (line_table,
   5496 							right_quote_byte_col));
   5497     layout test_layout (&dc, &richloc, DK_ERROR);
   5498     test_layout.print_line (1);
   5499     ASSERT_STREQ ("            This: `      ' is a tab.\n"
   5500 		  "                         ^\n",
   5501 		  pp_formatted_text (dc.printer));
   5502   }
   5503 }
   5504 
   5505 /* Verify that the escaping machinery can cope with a variety of different
   5506    invalid bytes.  */
   5507 
   5508 static void
   5509 test_escaping_bytes_1 (const line_table_case &case_)
   5510 {
   5511   const char content[] = "before\0\1\2\3\r\x80\xff""after\n";
   5512   const size_t sz = sizeof (content);
   5513   temp_source_file tmp (SELFTEST_LOCATION, ".c", content, sz);
   5514   line_table_test ltt (case_);
   5515   const line_map_ordinary *ord_map = linemap_check_ordinary
   5516     (linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0));
   5517   linemap_line_start (line_table, 1, 100);
   5518 
   5519   location_t finish
   5520     = linemap_position_for_line_and_column (line_table, ord_map, 1,
   5521 					    strlen (content));
   5522 
   5523   if (finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
   5524     return;
   5525 
   5526   /* Locations of the NUL and \r bytes.  */
   5527   location_t nul_loc
   5528     = linemap_position_for_line_and_column (line_table, ord_map, 1, 7);
   5529   location_t r_loc
   5530     = linemap_position_for_line_and_column (line_table, ord_map, 1, 11);
   5531   gcc_rich_location richloc (nul_loc);
   5532   richloc.add_range (r_loc);
   5533 
   5534   {
   5535     test_diagnostic_context dc;
   5536     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5537     ASSERT_STREQ (" before \1\2\3 \x80\xff""after\n"
   5538 		  "       ^   ~\n",
   5539 		  pp_formatted_text (dc.printer));
   5540   }
   5541   richloc.set_escape_on_output (true);
   5542   {
   5543     test_diagnostic_context dc;
   5544     dc.escape_format = DIAGNOSTICS_ESCAPE_FORMAT_UNICODE;
   5545     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5546     ASSERT_STREQ
   5547       (" before<U+0000><U+0001><U+0002><U+0003><U+000D><80><ff>after\n"
   5548        "       ^~~~~~~~                        ~~~~~~~~\n",
   5549        pp_formatted_text (dc.printer));
   5550   }
   5551   {
   5552     test_diagnostic_context dc;
   5553     dc.escape_format = DIAGNOSTICS_ESCAPE_FORMAT_BYTES;
   5554     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5555     ASSERT_STREQ (" before<00><01><02><03><0d><80><ff>after\n"
   5556 		  "       ^~~~            ~~~~\n",
   5557 		  pp_formatted_text (dc.printer));
   5558   }
   5559 }
   5560 
   5561 /* As above, but verify that we handle the initial byte of a line
   5562    correctly.  */
   5563 
   5564 static void
   5565 test_escaping_bytes_2 (const line_table_case &case_)
   5566 {
   5567   const char content[]  = "\0after\n";
   5568   const size_t sz = sizeof (content);
   5569   temp_source_file tmp (SELFTEST_LOCATION, ".c", content, sz);
   5570   line_table_test ltt (case_);
   5571   const line_map_ordinary *ord_map = linemap_check_ordinary
   5572     (linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0));
   5573   linemap_line_start (line_table, 1, 100);
   5574 
   5575   location_t finish
   5576     = linemap_position_for_line_and_column (line_table, ord_map, 1,
   5577 					    strlen (content));
   5578 
   5579   if (finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
   5580     return;
   5581 
   5582   /* Location of the NUL byte.  */
   5583   location_t nul_loc
   5584     = linemap_position_for_line_and_column (line_table, ord_map, 1, 1);
   5585   gcc_rich_location richloc (nul_loc);
   5586 
   5587   {
   5588     test_diagnostic_context dc;
   5589     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5590     ASSERT_STREQ ("  after\n"
   5591 		  " ^\n",
   5592 		  pp_formatted_text (dc.printer));
   5593   }
   5594   richloc.set_escape_on_output (true);
   5595   {
   5596     test_diagnostic_context dc;
   5597     dc.escape_format = DIAGNOSTICS_ESCAPE_FORMAT_UNICODE;
   5598     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5599     ASSERT_STREQ (" <U+0000>after\n"
   5600 		  " ^~~~~~~~\n",
   5601 		  pp_formatted_text (dc.printer));
   5602   }
   5603   {
   5604     test_diagnostic_context dc;
   5605     dc.escape_format = DIAGNOSTICS_ESCAPE_FORMAT_BYTES;
   5606     diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5607     ASSERT_STREQ (" <00>after\n"
   5608 		  " ^~~~\n",
   5609 		  pp_formatted_text (dc.printer));
   5610   }
   5611 }
   5612 
   5613 /* Verify that line numbers are correctly printed for the case of
   5614    a multiline range in which the width of the line numbers changes
   5615    (e.g. from "9" to "10").  */
   5616 
   5617 static void
   5618 test_line_numbers_multiline_range ()
   5619 {
   5620   /* Create a tempfile and write some text to it.  */
   5621   pretty_printer pp;
   5622   for (int i = 0; i < 20; i++)
   5623     /* .........0000000001111111.
   5624    .............1234567890123456.  */
   5625     pp_printf (&pp, "this is line %i\n", i + 1);
   5626   temp_source_file tmp (SELFTEST_LOCATION, ".txt", pp_formatted_text (&pp));
   5627   line_table_test ltt;
   5628 
   5629   const line_map_ordinary *ord_map = linemap_check_ordinary
   5630     (linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0));
   5631   linemap_line_start (line_table, 1, 100);
   5632 
   5633   /* Create a multi-line location, starting at the "line" of line 9, with
   5634      a caret on the "is" of line 10, finishing on the "this" line 11.  */
   5635 
   5636   location_t start
   5637     = linemap_position_for_line_and_column (line_table, ord_map, 9, 9);
   5638   location_t caret
   5639     = linemap_position_for_line_and_column (line_table, ord_map, 10, 6);
   5640   location_t finish
   5641     = linemap_position_for_line_and_column (line_table, ord_map, 11, 4);
   5642   location_t loc = make_location (caret, start, finish);
   5643 
   5644   test_diagnostic_context dc;
   5645   dc.show_line_numbers_p = true;
   5646   dc.min_margin_width = 0;
   5647   gcc_rich_location richloc (loc);
   5648   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   5649   ASSERT_STREQ (" 9 | this is line 9\n"
   5650 		"   |         ~~~~~~\n"
   5651 		"10 | this is line 10\n"
   5652 		"   | ~~~~~^~~~~~~~~~\n"
   5653 		"11 | this is line 11\n"
   5654 		"   | ~~~~  \n",
   5655 		pp_formatted_text (dc.printer));
   5656 }
   5657 
   5658 /* Run all of the selftests within this file.  */
   5659 
   5660 void
   5661 diagnostic_show_locus_cc_tests ()
   5662 {
   5663   test_line_span ();
   5664 
   5665   test_layout_range_for_single_point ();
   5666   test_layout_range_for_single_line ();
   5667   test_layout_range_for_multiple_lines ();
   5668 
   5669   test_display_widths ();
   5670 
   5671   for_each_line_table_case (test_layout_x_offset_display_utf8);
   5672   for_each_line_table_case (test_layout_x_offset_display_tab);
   5673 
   5674   test_get_line_bytes_without_trailing_whitespace ();
   5675 
   5676   test_diagnostic_show_locus_unknown_location ();
   5677 
   5678   for_each_line_table_case (test_diagnostic_show_locus_one_liner);
   5679   for_each_line_table_case (test_diagnostic_show_locus_one_liner_utf8);
   5680   for_each_line_table_case (test_add_location_if_nearby);
   5681   for_each_line_table_case (test_diagnostic_show_locus_fixit_lines);
   5682   for_each_line_table_case (test_fixit_consolidation);
   5683   for_each_line_table_case (test_overlapped_fixit_printing);
   5684   for_each_line_table_case (test_overlapped_fixit_printing_utf8);
   5685   for_each_line_table_case (test_overlapped_fixit_printing_2);
   5686   for_each_line_table_case (test_fixit_insert_containing_newline);
   5687   for_each_line_table_case (test_fixit_insert_containing_newline_2);
   5688   for_each_line_table_case (test_fixit_replace_containing_newline);
   5689   for_each_line_table_case (test_fixit_deletion_affecting_newline);
   5690   for_each_line_table_case (test_tab_expansion);
   5691   for_each_line_table_case (test_escaping_bytes_1);
   5692   for_each_line_table_case (test_escaping_bytes_2);
   5693 
   5694   test_line_numbers_multiline_range ();
   5695 }
   5696 
   5697 } // namespace selftest
   5698 
   5699 #endif /* #if CHECKING_P */
   5700 
   5701 #if __GNUC__ >= 10
   5702 #  pragma GCC diagnostic pop
   5703 #endif
   5704