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