comparison gcc/diagnostic-show-locus.c @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
comparison
equal deleted inserted replaced
111:04ced10e8804 131:84e7813d76e9
1 /* Diagnostic subroutines for printing source-code 1 /* Diagnostic subroutines for printing source-code
2 Copyright (C) 1999-2017 Free Software Foundation, Inc. 2 Copyright (C) 1999-2018 Free Software Foundation, Inc.
3 Contributed by Gabriel Dos Reis <gdr@codesourcery.com> 3 Contributed by Gabriel Dos Reis <gdr@codesourcery.com>
4 4
5 This file is part of GCC. 5 This file is part of GCC.
6 6
7 GCC is free software; you can redistribute it and/or modify it under 7 GCC is free software; you can redistribute it and/or modify it under
27 #include "backtrace.h" 27 #include "backtrace.h"
28 #include "diagnostic.h" 28 #include "diagnostic.h"
29 #include "diagnostic-color.h" 29 #include "diagnostic-color.h"
30 #include "gcc-rich-location.h" 30 #include "gcc-rich-location.h"
31 #include "selftest.h" 31 #include "selftest.h"
32 #include "selftest-diagnostic.h"
32 33
33 #ifdef HAVE_TERMIOS_H 34 #ifdef HAVE_TERMIOS_H
34 # include <termios.h> 35 # include <termios.h>
35 #endif 36 #endif
36 37
112 public: 113 public:
113 layout_point (const expanded_location &exploc) 114 layout_point (const expanded_location &exploc)
114 : m_line (exploc.line), 115 : m_line (exploc.line),
115 m_column (exploc.column) {} 116 m_column (exploc.column) {}
116 117
117 int m_line; 118 linenum_type m_line;
118 int m_column; 119 int m_column;
119 }; 120 };
120 121
121 /* A class for use by "class layout" below: a filtered location_range. */ 122 /* A class for use by "class layout" below: a filtered location_range. */
122 123
123 class layout_range 124 class layout_range
124 { 125 {
125 public: 126 public:
126 layout_range (const expanded_location *start_exploc, 127 layout_range (const expanded_location *start_exploc,
127 const expanded_location *finish_exploc, 128 const expanded_location *finish_exploc,
128 bool show_caret_p, 129 enum range_display_kind range_display_kind,
129 const expanded_location *caret_exploc); 130 const expanded_location *caret_exploc,
130 131 unsigned original_idx,
131 bool contains_point (int row, int column) const; 132 const range_label *label);
132 bool intersects_line_p (int row) const; 133
134 bool contains_point (linenum_type row, int column) const;
135 bool intersects_line_p (linenum_type row) const;
133 136
134 layout_point m_start; 137 layout_point m_start;
135 layout_point m_finish; 138 layout_point m_finish;
136 bool m_show_caret_p; 139 enum range_display_kind m_range_display_kind;
137 layout_point m_caret; 140 layout_point m_caret;
141 unsigned m_original_idx;
142 const range_label *m_label;
138 }; 143 };
139 144
140 /* A struct for use by layout::print_source_line for telling 145 /* A struct for use by layout::print_source_line for telling
141 layout::print_annotation_line the extents of the source line that 146 layout::print_annotation_line the extents of the source line that
142 it printed, so that underlines can be clipped appropriately. */ 147 it printed, so that underlines can be clipped appropriately. */
169 174
170 static int comparator (const void *p1, const void *p2) 175 static int comparator (const void *p1, const void *p2)
171 { 176 {
172 const line_span *ls1 = (const line_span *)p1; 177 const line_span *ls1 = (const line_span *)p1;
173 const line_span *ls2 = (const line_span *)p2; 178 const line_span *ls2 = (const line_span *)p2;
174 int first_line_diff = (int)ls1->m_first_line - (int)ls2->m_first_line; 179 int first_line_cmp = compare (ls1->m_first_line, ls2->m_first_line);
175 if (first_line_diff) 180 if (first_line_cmp)
176 return first_line_diff; 181 return first_line_cmp;
177 return (int)ls1->m_last_line - (int)ls2->m_last_line; 182 return compare (ls1->m_last_line, ls2->m_last_line);
178 } 183 }
179 184
180 linenum_type m_first_line; 185 linenum_type m_first_line;
181 linenum_type m_last_line; 186 linenum_type m_last_line;
182 }; 187 };
188
189 #if CHECKING_P
190
191 /* Selftests for line_span. */
192
193 static void
194 test_line_span ()
195 {
196 line_span line_one (1, 1);
197 ASSERT_EQ (1, line_one.get_first_line ());
198 ASSERT_EQ (1, line_one.get_last_line ());
199 ASSERT_FALSE (line_one.contains_line_p (0));
200 ASSERT_TRUE (line_one.contains_line_p (1));
201 ASSERT_FALSE (line_one.contains_line_p (2));
202
203 line_span lines_1_to_3 (1, 3);
204 ASSERT_EQ (1, lines_1_to_3.get_first_line ());
205 ASSERT_EQ (3, lines_1_to_3.get_last_line ());
206 ASSERT_TRUE (lines_1_to_3.contains_line_p (1));
207 ASSERT_TRUE (lines_1_to_3.contains_line_p (3));
208
209 ASSERT_EQ (0, line_span::comparator (&line_one, &line_one));
210 ASSERT_GT (line_span::comparator (&lines_1_to_3, &line_one), 0);
211 ASSERT_LT (line_span::comparator (&line_one, &lines_1_to_3), 0);
212
213 /* A linenum > 2^31. */
214 const linenum_type LARGEST_LINE = 0xffffffff;
215 line_span largest_line (LARGEST_LINE, LARGEST_LINE);
216 ASSERT_EQ (LARGEST_LINE, largest_line.get_first_line ());
217 ASSERT_EQ (LARGEST_LINE, largest_line.get_last_line ());
218
219 ASSERT_GT (line_span::comparator (&largest_line, &line_one), 0);
220 ASSERT_LT (line_span::comparator (&line_one, &largest_line), 0);
221 }
222
223 #endif /* #if CHECKING_P */
183 224
184 /* A class to control the overall layout when printing a diagnostic. 225 /* A class to control the overall layout when printing a diagnostic.
185 226
186 The layout is determined within the constructor. 227 The layout is determined within the constructor.
187 It is then printed by repeatedly calling the "print_source_line", 228 It is then printed by repeatedly calling the "print_source_line",
195 layout (diagnostic_context *context, 236 layout (diagnostic_context *context,
196 rich_location *richloc, 237 rich_location *richloc,
197 diagnostic_t diagnostic_kind); 238 diagnostic_t diagnostic_kind);
198 239
199 bool maybe_add_location_range (const location_range *loc_range, 240 bool maybe_add_location_range (const location_range *loc_range,
241 unsigned original_idx,
200 bool restrict_to_current_line_spans); 242 bool restrict_to_current_line_spans);
201 243
202 int get_num_line_spans () const { return m_line_spans.length (); } 244 int get_num_line_spans () const { return m_line_spans.length (); }
203 const line_span *get_line_span (int idx) const { return &m_line_spans[idx]; } 245 const line_span *get_line_span (int idx) const { return &m_line_spans[idx]; }
204 246
247 void print_gap_in_line_numbering ();
205 bool print_heading_for_line_span_index_p (int line_span_idx) const; 248 bool print_heading_for_line_span_index_p (int line_span_idx) const;
206 249
207 expanded_location get_expanded_location (const line_span *) const; 250 expanded_location get_expanded_location (const line_span *) const;
208 251
209 void print_line (int row); 252 void print_line (linenum_type row);
210 253
211 private: 254 private:
212 bool will_show_line_p (int row) const; 255 bool will_show_line_p (linenum_type row) const;
213 void print_leading_fixits (int row); 256 void print_leading_fixits (linenum_type row);
214 void print_source_line (int row, const char *line, int line_width, 257 void print_source_line (linenum_type row, const char *line, int line_width,
215 line_bounds *lbounds_out); 258 line_bounds *lbounds_out);
216 bool should_print_annotation_line_p (int row) const; 259 bool should_print_annotation_line_p (linenum_type row) const;
217 void print_annotation_line (int row, const line_bounds lbounds); 260 void start_annotation_line (char margin_char = ' ') const;
218 void print_trailing_fixits (int row); 261 void print_annotation_line (linenum_type row, const line_bounds lbounds);
219 262 void print_any_labels (linenum_type row);
220 bool annotation_line_showed_range_p (int line, int start_column, 263 void print_trailing_fixits (linenum_type row);
264
265 bool annotation_line_showed_range_p (linenum_type line, int start_column,
221 int finish_column) const; 266 int finish_column) const;
222 void show_ruler (int max_column) const; 267 void show_ruler (int max_column) const;
223 268
224 bool validate_fixit_hint_p (const fixit_hint *hint); 269 bool validate_fixit_hint_p (const fixit_hint *hint);
225 270
227 272
228 void print_newline (); 273 void print_newline ();
229 274
230 bool 275 bool
231 get_state_at_point (/* Inputs. */ 276 get_state_at_point (/* Inputs. */
232 int row, int column, 277 linenum_type row, int column,
233 int first_non_ws, int last_non_ws, 278 int first_non_ws, int last_non_ws,
234 /* Outputs. */ 279 /* Outputs. */
235 point_state *out_state); 280 point_state *out_state);
236 281
237 int 282 int
238 get_x_bound_for_row (int row, int caret_column, 283 get_x_bound_for_row (linenum_type row, int caret_column,
239 int last_non_ws); 284 int last_non_ws);
240 285
241 void 286 void
242 move_to_column (int *column, int dest_column); 287 move_to_column (int *column, int dest_column, bool add_left_margin);
243 288
244 private: 289 private:
245 diagnostic_context *m_context; 290 diagnostic_context *m_context;
246 pretty_printer *m_pp; 291 pretty_printer *m_pp;
247 diagnostic_t m_diagnostic_kind;
248 location_t m_primary_loc; 292 location_t m_primary_loc;
249 expanded_location m_exploc; 293 expanded_location m_exploc;
250 colorizer m_colorizer; 294 colorizer m_colorizer;
251 bool m_colorize_source_p; 295 bool m_colorize_source_p;
296 bool m_show_labels_p;
297 bool m_show_line_numbers_p;
252 auto_vec <layout_range> m_layout_ranges; 298 auto_vec <layout_range> m_layout_ranges;
253 auto_vec <const fixit_hint *> m_fixit_hints; 299 auto_vec <const fixit_hint *> m_fixit_hints;
254 auto_vec <line_span> m_line_spans; 300 auto_vec <line_span> m_line_spans;
301 int m_linenum_width;
255 int m_x_offset; 302 int m_x_offset;
256 }; 303 };
257 304
258 /* Implementation of "class colorizer". */ 305 /* Implementation of "class colorizer". */
259 306
365 Initialize various layout_point fields from expanded_location 412 Initialize various layout_point fields from expanded_location
366 equivalents; we've already filtered on file. */ 413 equivalents; we've already filtered on file. */
367 414
368 layout_range::layout_range (const expanded_location *start_exploc, 415 layout_range::layout_range (const expanded_location *start_exploc,
369 const expanded_location *finish_exploc, 416 const expanded_location *finish_exploc,
370 bool show_caret_p, 417 enum range_display_kind range_display_kind,
371 const expanded_location *caret_exploc) 418 const expanded_location *caret_exploc,
419 unsigned original_idx,
420 const range_label *label)
372 : m_start (*start_exploc), 421 : m_start (*start_exploc),
373 m_finish (*finish_exploc), 422 m_finish (*finish_exploc),
374 m_show_caret_p (show_caret_p), 423 m_range_display_kind (range_display_kind),
375 m_caret (*caret_exploc) 424 m_caret (*caret_exploc),
425 m_original_idx (original_idx),
426 m_label (label)
376 { 427 {
377 } 428 }
378 429
379 /* Is (column, row) within the given range? 430 /* Is (column, row) within the given range?
380 We've already filtered on the file. 431 We've already filtered on the file.
414 - 'F' indicates the finish of the range (which is 465 - 'F' indicates the finish of the range (which is
415 within it). 466 within it).
416 - 'a' indicates a subsequent point *after* the range. */ 467 - 'a' indicates a subsequent point *after* the range. */
417 468
418 bool 469 bool
419 layout_range::contains_point (int row, int column) const 470 layout_range::contains_point (linenum_type row, int column) const
420 { 471 {
421 gcc_assert (m_start.m_line <= m_finish.m_line); 472 gcc_assert (m_start.m_line <= m_finish.m_line);
422 /* ...but the equivalent isn't true for the columns; 473 /* ...but the equivalent isn't true for the columns;
423 consider example B in the comment above. */ 474 consider example B in the comment above. */
424 475
475 } 526 }
476 527
477 /* Does this layout_range contain any part of line ROW? */ 528 /* Does this layout_range contain any part of line ROW? */
478 529
479 bool 530 bool
480 layout_range::intersects_line_p (int row) const 531 layout_range::intersects_line_p (linenum_type row) const
481 { 532 {
482 gcc_assert (m_start.m_line <= m_finish.m_line); 533 gcc_assert (m_start.m_line <= m_finish.m_line);
483 if (row < m_start.m_line) 534 if (row < m_start.m_line)
484 return false; 535 return false;
485 if (row > m_finish.m_line) 536 if (row > m_finish.m_line)
496 { 547 {
497 const expanded_location start_exploc 548 const expanded_location start_exploc
498 = {"test.c", start_line, start_col, NULL, false}; 549 = {"test.c", start_line, start_col, NULL, false};
499 const expanded_location finish_exploc 550 const expanded_location finish_exploc
500 = {"test.c", end_line, end_col, NULL, false}; 551 = {"test.c", end_line, end_col, NULL, false};
501 return layout_range (&start_exploc, &finish_exploc, false, 552 return layout_range (&start_exploc, &finish_exploc, SHOW_RANGE_WITHOUT_CARET,
502 &start_exploc); 553 &start_exploc, 0, NULL);
503 } 554 }
504 555
505 /* Selftests for layout_range::contains_point and 556 /* Selftests for layout_range::contains_point and
506 layout_range::intersects_line_p. */ 557 layout_range::intersects_line_p. */
507 558
636 { 687 {
637 int result = line_width; 688 int result = line_width;
638 while (result > 0) 689 while (result > 0)
639 { 690 {
640 char ch = line[result - 1]; 691 char ch = line[result - 1];
641 if (ch == ' ' || ch == '\t') 692 if (ch == ' ' || ch == '\t' || ch == '\r')
642 result--; 693 result--;
643 else 694 else
644 break; 695 break;
645 } 696 }
646 gcc_assert (result >= 0); 697 gcc_assert (result >= 0);
647 gcc_assert (result <= line_width); 698 gcc_assert (result <= line_width);
648 gcc_assert (result == 0 || 699 gcc_assert (result == 0 ||
649 (line[result - 1] != ' ' 700 (line[result - 1] != ' '
650 && line[result -1] != '\t')); 701 && line[result -1] != '\t'
702 && line[result -1] != '\r'));
651 return result; 703 return result;
652 } 704 }
653 705
654 #if CHECKING_P 706 #if CHECKING_P
655 707
670 test_get_line_width_without_trailing_whitespace () 722 test_get_line_width_without_trailing_whitespace ()
671 { 723 {
672 assert_eq ("", 0); 724 assert_eq ("", 0);
673 assert_eq (" ", 0); 725 assert_eq (" ", 0);
674 assert_eq ("\t", 0); 726 assert_eq ("\t", 0);
727 assert_eq ("\r", 0);
675 assert_eq ("hello world", 11); 728 assert_eq ("hello world", 11);
676 assert_eq ("hello world ", 11); 729 assert_eq ("hello world ", 11);
677 assert_eq ("hello world \t\t ", 11); 730 assert_eq ("hello world \t\t ", 11);
731 assert_eq ("hello world\r", 11);
678 } 732 }
679 733
680 #endif /* #if CHECKING_P */ 734 #endif /* #if CHECKING_P */
681 735
682 /* Helper function for layout's ctor, for sanitizing locations relative 736 /* Helper function for layout's ctor, for sanitizing locations relative
763 const fixit_hint * hint_a = *static_cast<const fixit_hint * const *> (p_a); 817 const fixit_hint * hint_a = *static_cast<const fixit_hint * const *> (p_a);
764 const fixit_hint * hint_b = *static_cast<const fixit_hint * const *> (p_b); 818 const fixit_hint * hint_b = *static_cast<const fixit_hint * const *> (p_b);
765 return hint_a->get_start_loc () - hint_b->get_start_loc (); 819 return hint_a->get_start_loc () - hint_b->get_start_loc ();
766 } 820 }
767 821
822 /* Get the number of digits in the decimal representation
823 of VALUE. */
824
825 static int
826 num_digits (int value)
827 {
828 /* Perhaps simpler to use log10 for this, but doing it this way avoids
829 using floating point. */
830 gcc_assert (value >= 0);
831
832 if (value == 0)
833 return 1;
834
835 int digits = 0;
836 while (value > 0)
837 {
838 digits++;
839 value /= 10;
840 }
841 return digits;
842 }
843
844
845 #if CHECKING_P
846
847 /* Selftest for num_digits. */
848
849 static void
850 test_num_digits ()
851 {
852 ASSERT_EQ (1, num_digits (0));
853 ASSERT_EQ (1, num_digits (9));
854 ASSERT_EQ (2, num_digits (10));
855 ASSERT_EQ (2, num_digits (99));
856 ASSERT_EQ (3, num_digits (100));
857 ASSERT_EQ (3, num_digits (999));
858 ASSERT_EQ (4, num_digits (1000));
859 ASSERT_EQ (4, num_digits (9999));
860 ASSERT_EQ (5, num_digits (10000));
861 ASSERT_EQ (5, num_digits (99999));
862 ASSERT_EQ (6, num_digits (100000));
863 ASSERT_EQ (6, num_digits (999999));
864 ASSERT_EQ (7, num_digits (1000000));
865 ASSERT_EQ (7, num_digits (9999999));
866 ASSERT_EQ (8, num_digits (10000000));
867 ASSERT_EQ (8, num_digits (99999999));
868 }
869
870 #endif /* #if CHECKING_P */
871
768 /* Implementation of class layout. */ 872 /* Implementation of class layout. */
769 873
770 /* Constructor for class layout. 874 /* Constructor for class layout.
771 875
772 Filter the ranges from the rich_location to those that we can 876 Filter the ranges from the rich_location to those that we can
779 layout::layout (diagnostic_context * context, 883 layout::layout (diagnostic_context * context,
780 rich_location *richloc, 884 rich_location *richloc,
781 diagnostic_t diagnostic_kind) 885 diagnostic_t diagnostic_kind)
782 : m_context (context), 886 : m_context (context),
783 m_pp (context->printer), 887 m_pp (context->printer),
784 m_diagnostic_kind (diagnostic_kind),
785 m_primary_loc (richloc->get_range (0)->m_loc), 888 m_primary_loc (richloc->get_range (0)->m_loc),
786 m_exploc (richloc->get_expanded_location (0)), 889 m_exploc (richloc->get_expanded_location (0)),
787 m_colorizer (context, diagnostic_kind), 890 m_colorizer (context, diagnostic_kind),
788 m_colorize_source_p (context->colorize_source_p), 891 m_colorize_source_p (context->colorize_source_p),
892 m_show_labels_p (context->show_labels_p),
893 m_show_line_numbers_p (context->show_line_numbers_p),
789 m_layout_ranges (richloc->get_num_locations ()), 894 m_layout_ranges (richloc->get_num_locations ()),
790 m_fixit_hints (richloc->get_num_fixit_hints ()), 895 m_fixit_hints (richloc->get_num_fixit_hints ()),
791 m_line_spans (1 + richloc->get_num_locations ()), 896 m_line_spans (1 + richloc->get_num_locations ()),
897 m_linenum_width (0),
792 m_x_offset (0) 898 m_x_offset (0)
793 { 899 {
794 for (unsigned int idx = 0; idx < richloc->get_num_locations (); idx++) 900 for (unsigned int idx = 0; idx < richloc->get_num_locations (); idx++)
795 { 901 {
796 /* This diagnostic printer can only cope with "sufficiently sane" ranges. 902 /* This diagnostic printer can only cope with "sufficiently sane" ranges.
797 Ignore any ranges that are awkward to handle. */ 903 Ignore any ranges that are awkward to handle. */
798 const location_range *loc_range = richloc->get_range (idx); 904 const location_range *loc_range = richloc->get_range (idx);
799 maybe_add_location_range (loc_range, false); 905 maybe_add_location_range (loc_range, idx, false);
800 } 906 }
801 907
802 /* Populate m_fixit_hints, filtering to only those that are in the 908 /* Populate m_fixit_hints, filtering to only those that are in the
803 same file. */ 909 same file. */
804 for (unsigned int i = 0; i < richloc->get_num_fixit_hints (); i++) 910 for (unsigned int i = 0; i < richloc->get_num_fixit_hints (); i++)
812 m_fixit_hints.qsort (fixit_cmp); 918 m_fixit_hints.qsort (fixit_cmp);
813 919
814 /* Populate m_line_spans. */ 920 /* Populate m_line_spans. */
815 calculate_line_spans (); 921 calculate_line_spans ();
816 922
923 /* Determine m_linenum_width. */
924 gcc_assert (m_line_spans.length () > 0);
925 const line_span *last_span = &m_line_spans[m_line_spans.length () - 1];
926 int highest_line = last_span->m_last_line;
927 if (highest_line < 0)
928 highest_line = 0;
929 m_linenum_width = num_digits (highest_line);
930 /* If we're showing jumps in the line-numbering, allow at least 3 chars. */
931 if (m_line_spans.length () > 1)
932 m_linenum_width = MAX (m_linenum_width, 3);
933 /* If there's a minimum margin width, apply it (subtracting 1 for the space
934 after the line number. */
935 m_linenum_width = MAX (m_linenum_width, context->min_margin_width - 1);
936
817 /* Adjust m_x_offset. 937 /* Adjust m_x_offset.
818 Center the primary caret to fit in max_width; all columns 938 Center the primary caret to fit in max_width; all columns
819 will be adjusted accordingly. */ 939 will be adjusted accordingly. */
820 int max_width = m_context->caret_max_width; 940 size_t max_width = m_context->caret_max_width;
821 int line_width; 941 char_span line = location_get_source_line (m_exploc.file, m_exploc.line);
822 const char *line = location_get_source_line (m_exploc.file, m_exploc.line, 942 if (line && (size_t)m_exploc.column <= line.length ())
823 &line_width); 943 {
824 if (line && m_exploc.column <= line_width) 944 size_t right_margin = CARET_LINE_MARGIN;
825 { 945 size_t column = m_exploc.column;
826 int right_margin = CARET_LINE_MARGIN; 946 if (m_show_line_numbers_p)
827 int column = m_exploc.column; 947 column += m_linenum_width + 2;
828 right_margin = MIN (line_width - column, right_margin); 948 right_margin = MIN (line.length () - column, right_margin);
829 right_margin = max_width - right_margin; 949 right_margin = max_width - right_margin;
830 if (line_width >= max_width && column > right_margin) 950 if (line.length () >= max_width && column > right_margin)
831 m_x_offset = column - right_margin; 951 m_x_offset = column - right_margin;
832 gcc_assert (m_x_offset >= 0); 952 gcc_assert (m_x_offset >= 0);
833 } 953 }
834 954
835 if (context->show_ruler_p) 955 if (context->show_ruler_p)
836 show_ruler (m_x_offset + max_width); 956 show_ruler (m_x_offset + max_width);
837 } 957 }
838 958
839 /* Attempt to add LOC_RANGE to m_layout_ranges, filtering them to 959 /* Attempt to add LOC_RANGE to m_layout_ranges, filtering them to
840 those that we can sanely print. 960 those that we can sanely print.
961
962 ORIGINAL_IDX is the index of LOC_RANGE within its rich_location,
963 (for use as extrinsic state by label ranges FIXME).
841 964
842 If RESTRICT_TO_CURRENT_LINE_SPANS is true, then LOC_RANGE is also 965 If RESTRICT_TO_CURRENT_LINE_SPANS is true, then LOC_RANGE is also
843 filtered against this layout instance's current line spans: it 966 filtered against this layout instance's current line spans: it
844 will only be added if the location is fully within the lines 967 will only be added if the location is fully within the lines
845 already specified by other locations. 968 already specified by other locations.
846 969
847 Return true iff LOC_RANGE was added. */ 970 Return true iff LOC_RANGE was added. */
848 971
849 bool 972 bool
850 layout::maybe_add_location_range (const location_range *loc_range, 973 layout::maybe_add_location_range (const location_range *loc_range,
974 unsigned original_idx,
851 bool restrict_to_current_line_spans) 975 bool restrict_to_current_line_spans)
852 { 976 {
853 gcc_assert (loc_range); 977 gcc_assert (loc_range);
854 978
855 /* Split the "range" into caret and range information. */ 979 /* Split the "range" into caret and range information. */
870 location of this diagnostic, ignore the range. */ 994 location of this diagnostic, ignore the range. */
871 if (start.file != m_exploc.file) 995 if (start.file != m_exploc.file)
872 return false; 996 return false;
873 if (finish.file != m_exploc.file) 997 if (finish.file != m_exploc.file)
874 return false; 998 return false;
875 if (loc_range->m_show_caret_p) 999 if (loc_range->m_range_display_kind == SHOW_RANGE_WITH_CARET)
876 if (caret.file != m_exploc.file) 1000 if (caret.file != m_exploc.file)
877 return false; 1001 return false;
878 1002
879 /* Sanitize the caret location for non-primary ranges. */ 1003 /* Sanitize the caret location for non-primary ranges. */
880 if (m_layout_ranges.length () > 0) 1004 if (m_layout_ranges.length () > 0)
881 if (loc_range->m_show_caret_p) 1005 if (loc_range->m_range_display_kind == SHOW_RANGE_WITH_CARET)
882 if (!compatible_locations_p (loc_range->m_loc, m_primary_loc)) 1006 if (!compatible_locations_p (loc_range->m_loc, m_primary_loc))
883 /* Discard any non-primary ranges that can't be printed 1007 /* Discard any non-primary ranges that can't be printed
884 sanely relative to the primary location. */ 1008 sanely relative to the primary location. */
885 return false; 1009 return false;
886 1010
887 /* Everything is now known to be in the correct source file, 1011 /* Everything is now known to be in the correct source file,
888 but it may require further sanitization. */ 1012 but it may require further sanitization. */
889 layout_range ri (&start, &finish, loc_range->m_show_caret_p, &caret); 1013 layout_range ri (&start, &finish, loc_range->m_range_display_kind, &caret,
1014 original_idx, loc_range->m_label);
890 1015
891 /* If we have a range that finishes before it starts (perhaps 1016 /* If we have a range that finishes before it starts (perhaps
892 from something built via macro expansion), printing the 1017 from something built via macro expansion), printing the
893 range is likely to be nonsensical. Also, attempting to do so 1018 range is likely to be nonsensical. Also, attempting to do so
894 breaks assumptions within the printing code (PR c/68473). 1019 breaks assumptions within the printing code (PR c/68473).
920 { 1045 {
921 if (!will_show_line_p (start.line)) 1046 if (!will_show_line_p (start.line))
922 return false; 1047 return false;
923 if (!will_show_line_p (finish.line)) 1048 if (!will_show_line_p (finish.line))
924 return false; 1049 return false;
925 if (loc_range->m_show_caret_p) 1050 if (loc_range->m_range_display_kind == SHOW_RANGE_WITH_CARET)
926 if (!will_show_line_p (caret.line)) 1051 if (!will_show_line_p (caret.line))
927 return false; 1052 return false;
928 } 1053 }
929 1054
930 /* Passed all the tests; add the range to m_layout_ranges so that 1055 /* Passed all the tests; add the range to m_layout_ranges so that
934 } 1059 }
935 1060
936 /* Return true iff ROW is within one of the line spans for this layout. */ 1061 /* Return true iff ROW is within one of the line spans for this layout. */
937 1062
938 bool 1063 bool
939 layout::will_show_line_p (int row) const 1064 layout::will_show_line_p (linenum_type row) const
940 { 1065 {
941 for (int line_span_idx = 0; line_span_idx < get_num_line_spans (); 1066 for (int line_span_idx = 0; line_span_idx < get_num_line_spans ();
942 line_span_idx++) 1067 line_span_idx++)
943 { 1068 {
944 const line_span *line_span = get_line_span (line_span_idx); 1069 const line_span *line_span = get_line_span (line_span_idx);
945 if (line_span->contains_line_p (row)) 1070 if (line_span->contains_line_p (row))
946 return true; 1071 return true;
947 } 1072 }
948 return false; 1073 return false;
1074 }
1075
1076 /* Print a line showing a gap in the line numbers, for showing the boundary
1077 between two line spans. */
1078
1079 void
1080 layout::print_gap_in_line_numbering ()
1081 {
1082 gcc_assert (m_show_line_numbers_p);
1083
1084 for (int i = 0; i < m_linenum_width + 1; i++)
1085 pp_character (m_pp, '.');
1086
1087 pp_newline (m_pp);
949 } 1088 }
950 1089
951 /* Return true iff we should print a heading when starting the 1090 /* Return true iff we should print a heading when starting the
952 line span with the given index. */ 1091 line span with the given index. */
953 1092
1028 1167
1029 static line_span 1168 static line_span
1030 get_line_span_for_fixit_hint (const fixit_hint *hint) 1169 get_line_span_for_fixit_hint (const fixit_hint *hint)
1031 { 1170 {
1032 gcc_assert (hint); 1171 gcc_assert (hint);
1033 return line_span (LOCATION_LINE (hint->get_start_loc ()), 1172
1173 int start_line = LOCATION_LINE (hint->get_start_loc ());
1174
1175 /* For line-insertion fix-it hints, add the previous line to the
1176 span, to give the user more context on the proposed change. */
1177 if (hint->ends_with_newline_p ())
1178 if (start_line > 1)
1179 start_line--;
1180
1181 return line_span (start_line,
1034 LOCATION_LINE (hint->get_next_loc ())); 1182 LOCATION_LINE (hint->get_next_loc ()));
1035 } 1183 }
1036 1184
1037 /* We want to print the pertinent source code at a diagnostic. The 1185 /* We want to print the pertinent source code at a diagnostic. The
1038 rich_location can contain multiple locations. This will have been 1186 rich_location can contain multiple locations. This will have been
1043 as a collection of "spans" of lines. 1191 as a collection of "spans" of lines.
1044 1192
1045 This function populates m_line_spans with an ordered, disjoint list of 1193 This function populates m_line_spans with an ordered, disjoint list of
1046 the line spans of interest. 1194 the line spans of interest.
1047 1195
1048 For example, if the primary caret location is on line 7, with ranges 1196 Printing a gap between line spans takes one line, so, when printing
1049 covering lines 5-6 and lines 9-12: 1197 line numbers, we allow a gap of up to one line between spans when
1198 merging, since it makes more sense to print the source line rather than a
1199 "gap-in-line-numbering" line. When not printing line numbers, it's
1200 better to be more explicit about what's going on, so keeping them as
1201 separate spans is preferred.
1202
1203 For example, if the primary range is on lines 8-10, with secondary ranges
1204 covering lines 5-6 and lines 13-15:
1050 1205
1051 004 1206 004
1052 005 |RANGE 0 1207 005 |RANGE 1
1053 006 |RANGE 0 1208 006 |RANGE 1
1054 007 |PRIMARY CARET 1209 007
1055 008 1210 008 |PRIMARY RANGE
1056 009 |RANGE 1 1211 009 |PRIMARY CARET
1057 010 |RANGE 1 1212 010 |PRIMARY RANGE
1058 011 |RANGE 1 1213 011
1059 012 |RANGE 1 1214 012
1060 013 1215 013 |RANGE 2
1061 1216 014 |RANGE 2
1062 then we want two spans: lines 5-7 and lines 9-12. */ 1217 015 |RANGE 2
1218 016
1219
1220 With line numbering on, we want two spans: lines 5-10 and lines 13-15.
1221
1222 With line numbering off (with span headers), we want three spans: lines 5-6,
1223 lines 8-10, and lines 13-15. */
1063 1224
1064 void 1225 void
1065 layout::calculate_line_spans () 1226 layout::calculate_line_spans ()
1066 { 1227 {
1067 /* This should only be called once, by the ctor. */ 1228 /* This should only be called once, by the ctor. */
1097 for (unsigned int i = 1; i < tmp_spans.length (); i++) 1258 for (unsigned int i = 1; i < tmp_spans.length (); i++)
1098 { 1259 {
1099 line_span *current = &m_line_spans[m_line_spans.length () - 1]; 1260 line_span *current = &m_line_spans[m_line_spans.length () - 1];
1100 const line_span *next = &tmp_spans[i]; 1261 const line_span *next = &tmp_spans[i];
1101 gcc_assert (next->m_first_line >= current->m_first_line); 1262 gcc_assert (next->m_first_line >= current->m_first_line);
1102 if (next->m_first_line <= current->m_last_line + 1) 1263 const int merger_distance = m_show_line_numbers_p ? 1 : 0;
1264 if (next->m_first_line <= current->m_last_line + 1 + merger_distance)
1103 { 1265 {
1104 /* We can merge them. */ 1266 /* We can merge them. */
1105 if (next->m_last_line > current->m_last_line) 1267 if (next->m_last_line > current->m_last_line)
1106 current->m_last_line = next->m_last_line; 1268 current->m_last_line = next->m_last_line;
1107 } 1269 }
1132 populate *LBOUNDS_OUT. 1294 populate *LBOUNDS_OUT.
1133 LINE is the source line (not necessarily 0-terminated) and LINE_WIDTH 1295 LINE is the source line (not necessarily 0-terminated) and LINE_WIDTH
1134 is its width. */ 1296 is its width. */
1135 1297
1136 void 1298 void
1137 layout::print_source_line (int row, const char *line, int line_width, 1299 layout::print_source_line (linenum_type row, const char *line, int line_width,
1138 line_bounds *lbounds_out) 1300 line_bounds *lbounds_out)
1139 { 1301 {
1140 m_colorizer.set_normal_text (); 1302 m_colorizer.set_normal_text ();
1141 1303
1142 /* We will stop printing the source line at any trailing 1304 /* We will stop printing the source line at any trailing
1143 whitespace. */ 1305 whitespace. */
1144 line_width = get_line_width_without_trailing_whitespace (line, 1306 line_width = get_line_width_without_trailing_whitespace (line,
1145 line_width); 1307 line_width);
1146 line += m_x_offset; 1308 line += m_x_offset;
1147 1309
1148 pp_space (m_pp); 1310 if (m_show_line_numbers_p)
1311 {
1312 int width = num_digits (row);
1313 for (int i = 0; i < m_linenum_width - width; i++)
1314 pp_space (m_pp);
1315 pp_printf (m_pp, "%i | ", row);
1316 }
1317 else
1318 pp_space (m_pp);
1149 int first_non_ws = INT_MAX; 1319 int first_non_ws = INT_MAX;
1150 int last_non_ws = 0; 1320 int last_non_ws = 0;
1151 int column; 1321 int column;
1152 for (column = 1 + m_x_offset; column <= line_width; column++) 1322 for (column = 1 + m_x_offset; column <= line_width; column++)
1153 { 1323 {
1173 if (in_range_p) 1343 if (in_range_p)
1174 m_colorizer.set_range (state.range_idx); 1344 m_colorizer.set_range (state.range_idx);
1175 else 1345 else
1176 m_colorizer.set_normal_text (); 1346 m_colorizer.set_normal_text ();
1177 } 1347 }
1178 char c = *line == '\t' ? ' ' : *line; 1348 char c = *line;
1179 if (c == '\0') 1349 if (c == '\0' || c == '\t' || c == '\r')
1180 c = ' '; 1350 c = ' ';
1181 if (c != ' ') 1351 if (c != ' ')
1182 { 1352 {
1183 last_non_ws = column; 1353 last_non_ws = column;
1184 if (first_non_ws == INT_MAX) 1354 if (first_non_ws == INT_MAX)
1195 1365
1196 /* Determine if we should print an annotation line for ROW. 1366 /* Determine if we should print an annotation line for ROW.
1197 i.e. if any of m_layout_ranges contains ROW. */ 1367 i.e. if any of m_layout_ranges contains ROW. */
1198 1368
1199 bool 1369 bool
1200 layout::should_print_annotation_line_p (int row) const 1370 layout::should_print_annotation_line_p (linenum_type row) const
1201 { 1371 {
1202 layout_range *range; 1372 layout_range *range;
1203 int i; 1373 int i;
1204 FOR_EACH_VEC_ELT (m_layout_ranges, i, range) 1374 FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
1205 if (range->intersects_line_p (row)) 1375 {
1206 return true; 1376 if (range->m_range_display_kind == SHOW_LINES_WITHOUT_RANGE)
1377 return false;
1378 if (range->intersects_line_p (row))
1379 return true;
1380 }
1207 return false; 1381 return false;
1382 }
1383
1384 /* Begin an annotation line. If m_show_line_numbers_p, print the left
1385 margin, which is empty for annotation lines. Otherwise, do nothing. */
1386
1387 void
1388 layout::start_annotation_line (char margin_char) const
1389 {
1390 if (m_show_line_numbers_p)
1391 {
1392 /* Print the margin. If MARGIN_CHAR != ' ', then print up to 3
1393 of it, right-aligned, padded with spaces. */
1394 int i;
1395 for (i = 0; i < m_linenum_width - 3; i++)
1396 pp_space (m_pp);
1397 for (; i < m_linenum_width; i++)
1398 pp_character (m_pp, margin_char);
1399 pp_string (m_pp, " |");
1400 }
1208 } 1401 }
1209 1402
1210 /* Print a line consisting of the caret/underlines for the given 1403 /* Print a line consisting of the caret/underlines for the given
1211 source line. */ 1404 source line. */
1212 1405
1213 void 1406 void
1214 layout::print_annotation_line (int row, const line_bounds lbounds) 1407 layout::print_annotation_line (linenum_type row, const line_bounds lbounds)
1215 { 1408 {
1216 int x_bound = get_x_bound_for_row (row, m_exploc.column, 1409 int x_bound = get_x_bound_for_row (row, m_exploc.column,
1217 lbounds.m_last_non_ws); 1410 lbounds.m_last_non_ws);
1218 1411
1412 start_annotation_line ();
1219 pp_space (m_pp); 1413 pp_space (m_pp);
1414
1220 for (int column = 1 + m_x_offset; column < x_bound; column++) 1415 for (int column = 1 + m_x_offset; column < x_bound; column++)
1221 { 1416 {
1222 bool in_range_p; 1417 bool in_range_p;
1223 point_state state; 1418 point_state state;
1224 in_range_p = get_state_at_point (row, column, 1419 in_range_p = get_state_at_point (row, column,
1250 } 1445 }
1251 } 1446 }
1252 print_newline (); 1447 print_newline ();
1253 } 1448 }
1254 1449
1450 /* Implementation detail of layout::print_any_labels.
1451
1452 A label within the given row of source. */
1453
1454 struct line_label
1455 {
1456 line_label (int state_idx, int column, label_text text)
1457 : m_state_idx (state_idx), m_column (column),
1458 m_text (text), m_length (strlen (text.m_buffer)),
1459 m_label_line (0)
1460 {}
1461
1462 /* Sorting is primarily by column, then by state index. */
1463 static int comparator (const void *p1, const void *p2)
1464 {
1465 const line_label *ll1 = (const line_label *)p1;
1466 const line_label *ll2 = (const line_label *)p2;
1467 int column_cmp = compare (ll1->m_column, ll2->m_column);
1468 if (column_cmp)
1469 return column_cmp;
1470 return compare (ll1->m_state_idx, ll2->m_state_idx);
1471 }
1472
1473 int m_state_idx;
1474 int m_column;
1475 label_text m_text;
1476 size_t m_length;
1477 int m_label_line;
1478 };
1479
1480 /* Print any labels in this row. */
1481 void
1482 layout::print_any_labels (linenum_type row)
1483 {
1484 int i;
1485 auto_vec<line_label> labels;
1486
1487 /* Gather the labels that are to be printed into "labels". */
1488 {
1489 layout_range *range;
1490 FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
1491 {
1492 /* Most ranges don't have labels, so reject this first. */
1493 if (range->m_label == NULL)
1494 continue;
1495
1496 /* The range's caret must be on this line. */
1497 if (range->m_caret.m_line != row)
1498 continue;
1499
1500 /* Reject labels that aren't fully visible due to clipping
1501 by m_x_offset. */
1502 if (range->m_caret.m_column <= m_x_offset)
1503 continue;
1504
1505 label_text text;
1506 text = range->m_label->get_text (range->m_original_idx);
1507
1508 /* Allow for labels that return NULL from their get_text
1509 implementation (so e.g. such labels can control their own
1510 visibility). */
1511 if (text.m_buffer == NULL)
1512 continue;
1513
1514 labels.safe_push (line_label (i, range->m_caret.m_column, text));
1515 }
1516 }
1517
1518 /* Bail out if there are no labels on this row. */
1519 if (labels.length () == 0)
1520 return;
1521
1522 /* Sort them. */
1523 labels.qsort(line_label::comparator);
1524
1525 /* Figure out how many "label lines" we need, and which
1526 one each label is printed in.
1527
1528 For example, if the labels aren't too densely packed,
1529 we can fit them on the same line, giving two "label lines":
1530
1531 foo + bar
1532 ~~~ ~~~
1533 | | : label line 0
1534 l0 l1 : label line 1
1535
1536 If they would touch each other or overlap, then we need
1537 additional "label lines":
1538
1539 foo + bar
1540 ~~~ ~~~
1541 | | : label line 0
1542 | label 1 : label line 1
1543 label 0 : label line 2
1544
1545 Place the final label on label line 1, and work backwards, adding
1546 label lines as needed.
1547
1548 If multiple labels are at the same place, put them on separate
1549 label lines:
1550
1551 foo + bar
1552 ^ : label line 0
1553 | : label line 1
1554 label 1 : label line 2
1555 label 0 : label line 3. */
1556
1557 int max_label_line = 1;
1558 {
1559 int next_column = INT_MAX;
1560 line_label *label;
1561 FOR_EACH_VEC_ELT_REVERSE (labels, i, label)
1562 {
1563 /* Would this label "touch" or overlap the next label? */
1564 if (label->m_column + label->m_length >= (size_t)next_column)
1565 max_label_line++;
1566
1567 label->m_label_line = max_label_line;
1568 next_column = label->m_column;
1569 }
1570 }
1571
1572 /* Print the "label lines". For each label within the line, print
1573 either a vertical bar ('|') for the labels that are lower down, or the
1574 labels themselves once we've reached their line. */
1575 {
1576 /* Keep track of in which column we last printed a vertical bar.
1577 This allows us to suppress duplicate vertical bars for the case
1578 where multiple labels are on one column. */
1579 int last_vbar = 0;
1580 for (int label_line = 0; label_line <= max_label_line; label_line++)
1581 {
1582 start_annotation_line ();
1583 pp_space (m_pp);
1584 int column = 1 + m_x_offset;
1585 line_label *label;
1586 FOR_EACH_VEC_ELT (labels, i, label)
1587 {
1588 if (label_line > label->m_label_line)
1589 /* We've printed all the labels for this label line. */
1590 break;
1591
1592 if (label_line == label->m_label_line)
1593 {
1594 gcc_assert (column <= label->m_column);
1595 move_to_column (&column, label->m_column, true);
1596 m_colorizer.set_range (label->m_state_idx);
1597 pp_string (m_pp, label->m_text.m_buffer);
1598 m_colorizer.set_normal_text ();
1599 column += label->m_length;
1600 }
1601 else if (label->m_column != last_vbar)
1602 {
1603 gcc_assert (column <= label->m_column);
1604 move_to_column (&column, label->m_column, true);
1605 m_colorizer.set_range (label->m_state_idx);
1606 pp_character (m_pp, '|');
1607 m_colorizer.set_normal_text ();
1608 last_vbar = column;
1609 column++;
1610 }
1611 }
1612 print_newline ();
1613 }
1614 }
1615
1616 /* Clean up. */
1617 {
1618 line_label *label;
1619 FOR_EACH_VEC_ELT (labels, i, label)
1620 label->m_text.maybe_free ();
1621 }
1622 }
1623
1255 /* If there are any fixit hints inserting new lines before source line ROW, 1624 /* If there are any fixit hints inserting new lines before source line ROW,
1256 print them. 1625 print them.
1257 1626
1258 They are printed on lines of their own, before the source line 1627 They are printed on lines of their own, before the source line
1259 itself, with a leading '+'. */ 1628 itself, with a leading '+'. */
1260 1629
1261 void 1630 void
1262 layout::print_leading_fixits (int row) 1631 layout::print_leading_fixits (linenum_type row)
1263 { 1632 {
1264 for (unsigned int i = 0; i < m_fixit_hints.length (); i++) 1633 for (unsigned int i = 0; i < m_fixit_hints.length (); i++)
1265 { 1634 {
1266 const fixit_hint *hint = m_fixit_hints[i]; 1635 const fixit_hint *hint = m_fixit_hints[i];
1267 1636
1276 /* Printing the '+' with normal colorization 1645 /* Printing the '+' with normal colorization
1277 and the inserted line with "insert" colorization 1646 and the inserted line with "insert" colorization
1278 helps them stand out from each other, and from 1647 helps them stand out from each other, and from
1279 the surrounding text. */ 1648 the surrounding text. */
1280 m_colorizer.set_normal_text (); 1649 m_colorizer.set_normal_text ();
1650 start_annotation_line ('+');
1281 pp_character (m_pp, '+'); 1651 pp_character (m_pp, '+');
1282 m_colorizer.set_fixit_insert (); 1652 m_colorizer.set_fixit_insert ();
1283 /* Print all but the trailing newline of the fix-it hint. 1653 /* Print all but the trailing newline of the fix-it hint.
1284 We have to print the newline separately to avoid 1654 We have to print the newline separately to avoid
1285 getting additional pp prefixes printed. */ 1655 getting additional pp prefixes printed. */
1295 1665
1296 Determine if the annotation line printed for LINE contained 1666 Determine if the annotation line printed for LINE contained
1297 the exact range from START_COLUMN to FINISH_COLUMN. */ 1667 the exact range from START_COLUMN to FINISH_COLUMN. */
1298 1668
1299 bool 1669 bool
1300 layout::annotation_line_showed_range_p (int line, int start_column, 1670 layout::annotation_line_showed_range_p (linenum_type line, int start_column,
1301 int finish_column) const 1671 int finish_column) const
1302 { 1672 {
1303 layout_range *range; 1673 layout_range *range;
1304 int i; 1674 int i;
1305 FOR_EACH_VEC_ELT (m_layout_ranges, i, range) 1675 FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
1441 return column_range (start_column, 1811 return column_range (start_column,
1442 MAX (finish_column, final_hint_column)); 1812 MAX (finish_column, final_hint_column));
1443 } 1813 }
1444 } 1814 }
1445 1815
1446 /* A struct capturing the bounds of a buffer, to allow for run-time
1447 bounds-checking in a checked build. */
1448
1449 struct char_span
1450 {
1451 char_span (const char *ptr, size_t n_elts) : m_ptr (ptr), m_n_elts (n_elts) {}
1452
1453 char_span subspan (int offset, int n_elts)
1454 {
1455 gcc_assert (offset >= 0);
1456 gcc_assert (offset < (int)m_n_elts);
1457 gcc_assert (n_elts >= 0);
1458 gcc_assert (offset + n_elts <= (int)m_n_elts);
1459 return char_span (m_ptr + offset, n_elts);
1460 }
1461
1462 const char *m_ptr;
1463 size_t m_n_elts;
1464 };
1465
1466 /* A correction on a particular line. 1816 /* A correction on a particular line.
1467 This describes a plan for how to print one or more fixit_hint 1817 This describes a plan for how to print one or more fixit_hint
1468 instances that affected the line, potentially consolidating hints 1818 instances that affected the line, potentially consolidating hints
1469 into corrections to make the result easier for the user to read. */ 1819 into corrections to make the result easier for the user to read. */
1470 1820
1492 void ensure_terminated (); 1842 void ensure_terminated ();
1493 1843
1494 void overwrite (int dst_offset, const char_span &src_span) 1844 void overwrite (int dst_offset, const char_span &src_span)
1495 { 1845 {
1496 gcc_assert (dst_offset >= 0); 1846 gcc_assert (dst_offset >= 0);
1497 gcc_assert (dst_offset + src_span.m_n_elts < m_alloc_sz); 1847 gcc_assert (dst_offset + src_span.length () < m_alloc_sz);
1498 memcpy (m_text + dst_offset, src_span.m_ptr, 1848 memcpy (m_text + dst_offset, src_span.get_buffer (),
1499 src_span.m_n_elts); 1849 src_span.length ());
1500 } 1850 }
1501 1851
1502 /* If insert, then start: the column before which the text 1852 /* If insert, then start: the column before which the text
1503 is to be inserted, and finish is offset by the length of 1853 is to be inserted, and finish is offset by the length of
1504 the replacement. 1854 the replacement.
1546 This is used by layout::print_trailing_fixits for planning 1896 This is used by layout::print_trailing_fixits for planning
1547 how to print the fix-it hints affecting the line. */ 1897 how to print the fix-it hints affecting the line. */
1548 1898
1549 struct line_corrections 1899 struct line_corrections
1550 { 1900 {
1551 line_corrections (const char *filename, int row) 1901 line_corrections (const char *filename, linenum_type row)
1552 : m_filename (filename), m_row (row) 1902 : m_filename (filename), m_row (row)
1553 {} 1903 {}
1554 ~line_corrections (); 1904 ~line_corrections ();
1555 1905
1556 void add_hint (const fixit_hint *hint); 1906 void add_hint (const fixit_hint *hint);
1557 1907
1558 const char *m_filename; 1908 const char *m_filename;
1559 int m_row; 1909 linenum_type m_row;
1560 auto_vec <correction *> m_corrections; 1910 auto_vec <correction *> m_corrections;
1561 }; 1911 };
1562 1912
1563 /* struct line_corrections. */ 1913 /* struct line_corrections. */
1564 1914
1585 1935
1586 /* source_line's ctor. */ 1936 /* source_line's ctor. */
1587 1937
1588 source_line::source_line (const char *filename, int line) 1938 source_line::source_line (const char *filename, int line)
1589 { 1939 {
1590 chars = location_get_source_line (filename, line, &width); 1940 char_span span = location_get_source_line (filename, line);
1941 chars = span.get_buffer ();
1942 width = span.length ();
1591 } 1943 }
1592 1944
1593 /* Add HINT to the corrections for this line. 1945 /* Add HINT to the corrections for this line.
1594 Attempt to consolidate nearby hints so that they will not 1946 Attempt to consolidate nearby hints so that they will not
1595 overlap with printed. */ 1947 overlap with printed. */
1668 starting new lines if necessary. 2020 starting new lines if necessary.
1669 Fix-it hints that insert new lines are handled separately, 2021 Fix-it hints that insert new lines are handled separately,
1670 in layout::print_leading_fixits. */ 2022 in layout::print_leading_fixits. */
1671 2023
1672 void 2024 void
1673 layout::print_trailing_fixits (int row) 2025 layout::print_trailing_fixits (linenum_type row)
1674 { 2026 {
1675 /* Build a list of correction instances for the line, 2027 /* Build a list of correction instances for the line,
1676 potentially consolidating hints (for the sake of readability). */ 2028 potentially consolidating hints (for the sake of readability). */
1677 line_corrections corrections (m_exploc.file, row); 2029 line_corrections corrections (m_exploc.file, row);
1678 for (unsigned int i = 0; i < m_fixit_hints.length (); i++) 2030 for (unsigned int i = 0; i < m_fixit_hints.length (); i++)
1688 } 2040 }
1689 2041
1690 /* Now print the corrections. */ 2042 /* Now print the corrections. */
1691 unsigned i; 2043 unsigned i;
1692 correction *c; 2044 correction *c;
1693 int column = 0; 2045 int column = m_x_offset;
2046
2047 if (!corrections.m_corrections.is_empty ())
2048 start_annotation_line ();
1694 2049
1695 FOR_EACH_VEC_ELT (corrections.m_corrections, i, c) 2050 FOR_EACH_VEC_ELT (corrections.m_corrections, i, c)
1696 { 2051 {
1697 /* For now we assume each fixit hint can only touch one line. */ 2052 /* For now we assume each fixit hint can only touch one line. */
1698 if (c->insertion_p ()) 2053 if (c->insertion_p ())
1699 { 2054 {
1700 /* This assumes the insertion just affects one line. */ 2055 /* This assumes the insertion just affects one line. */
1701 int start_column = c->m_printed_columns.start; 2056 int start_column = c->m_printed_columns.start;
1702 move_to_column (&column, start_column); 2057 move_to_column (&column, start_column, true);
1703 m_colorizer.set_fixit_insert (); 2058 m_colorizer.set_fixit_insert ();
1704 pp_string (m_pp, c->m_text); 2059 pp_string (m_pp, c->m_text);
1705 m_colorizer.set_normal_text (); 2060 m_colorizer.set_normal_text ();
1706 column += c->m_len; 2061 column += c->m_len;
1707 } 2062 }
1715 int finish_column = c->m_affected_columns.finish; 2070 int finish_column = c->m_affected_columns.finish;
1716 if (!annotation_line_showed_range_p (row, start_column, 2071 if (!annotation_line_showed_range_p (row, start_column,
1717 finish_column) 2072 finish_column)
1718 || c->m_len == 0) 2073 || c->m_len == 0)
1719 { 2074 {
1720 move_to_column (&column, start_column); 2075 move_to_column (&column, start_column, true);
1721 m_colorizer.set_fixit_delete (); 2076 m_colorizer.set_fixit_delete ();
1722 for (; column <= finish_column; column++) 2077 for (; column <= finish_column; column++)
1723 pp_character (m_pp, '-'); 2078 pp_character (m_pp, '-');
1724 m_colorizer.set_normal_text (); 2079 m_colorizer.set_normal_text ();
1725 } 2080 }
1726 /* Print the replacement text. REPLACE also covers 2081 /* Print the replacement text. REPLACE also covers
1727 removals, so only do this extra work (potentially starting 2082 removals, so only do this extra work (potentially starting
1728 a new line) if we have actual replacement text. */ 2083 a new line) if we have actual replacement text. */
1729 if (c->m_len > 0) 2084 if (c->m_len > 0)
1730 { 2085 {
1731 move_to_column (&column, start_column); 2086 move_to_column (&column, start_column, true);
1732 m_colorizer.set_fixit_insert (); 2087 m_colorizer.set_fixit_insert ();
1733 pp_string (m_pp, c->m_text); 2088 pp_string (m_pp, c->m_text);
1734 m_colorizer.set_normal_text (); 2089 m_colorizer.set_normal_text ();
1735 column += c->m_len; 2090 column += c->m_len;
1736 } 2091 }
1737 } 2092 }
1738 } 2093 }
1739 2094
1740 /* Add a trailing newline, if necessary. */ 2095 /* Add a trailing newline, if necessary. */
1741 move_to_column (&column, 0); 2096 move_to_column (&column, 0, false);
1742 } 2097 }
1743 2098
1744 /* Disable any colorization and emit a newline. */ 2099 /* Disable any colorization and emit a newline. */
1745 2100
1746 void 2101 void
1755 range index, and whether we should draw the caret at 2110 range index, and whether we should draw the caret at
1756 (ROW/COLUMN) (as opposed to an underline). */ 2111 (ROW/COLUMN) (as opposed to an underline). */
1757 2112
1758 bool 2113 bool
1759 layout::get_state_at_point (/* Inputs. */ 2114 layout::get_state_at_point (/* Inputs. */
1760 int row, int column, 2115 linenum_type row, int column,
1761 int first_non_ws, int last_non_ws, 2116 int first_non_ws, int last_non_ws,
1762 /* Outputs. */ 2117 /* Outputs. */
1763 point_state *out_state) 2118 point_state *out_state)
1764 { 2119 {
1765 layout_range *range; 2120 layout_range *range;
1766 int i; 2121 int i;
1767 FOR_EACH_VEC_ELT (m_layout_ranges, i, range) 2122 FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
1768 { 2123 {
2124 if (range->m_range_display_kind == SHOW_LINES_WITHOUT_RANGE)
2125 /* Bail out early, so that such ranges don't affect underlining or
2126 source colorization. */
2127 continue;
2128
1769 if (range->contains_point (row, column)) 2129 if (range->contains_point (row, column))
1770 { 2130 {
1771 out_state->range_idx = i; 2131 out_state->range_idx = i;
1772 2132
1773 /* Are we at the range's caret? is it visible? */ 2133 /* Are we at the range's caret? is it visible? */
1774 out_state->draw_caret_p = false; 2134 out_state->draw_caret_p = false;
1775 if (range->m_show_caret_p 2135 if (range->m_range_display_kind == SHOW_RANGE_WITH_CARET
1776 && row == range->m_caret.m_line 2136 && row == range->m_caret.m_line
1777 && column == range->m_caret.m_column) 2137 && column == range->m_caret.m_column)
1778 out_state->draw_caret_p = true; 2138 out_state->draw_caret_p = true;
1779 2139
1780 /* Within a multiline range, don't display any underline 2140 /* Within a multiline range, don't display any underline
1800 CARET_COLUMN is the column of range 0's caret. 2160 CARET_COLUMN is the column of range 0's caret.
1801 LAST_NON_WS_COLUMN is the last column containing a non-whitespace 2161 LAST_NON_WS_COLUMN is the last column containing a non-whitespace
1802 character of source (as determined when printing the source line). */ 2162 character of source (as determined when printing the source line). */
1803 2163
1804 int 2164 int
1805 layout::get_x_bound_for_row (int row, int caret_column, 2165 layout::get_x_bound_for_row (linenum_type row, int caret_column,
1806 int last_non_ws_column) 2166 int last_non_ws_column)
1807 { 2167 {
1808 int result = caret_column + 1; 2168 int result = caret_column + 1;
1809 2169
1810 layout_range *range; 2170 layout_range *range;
1833 return result; 2193 return result;
1834 } 2194 }
1835 2195
1836 /* Given *COLUMN as an x-coordinate, print spaces to position 2196 /* Given *COLUMN as an x-coordinate, print spaces to position
1837 successive output at DEST_COLUMN, printing a newline if necessary, 2197 successive output at DEST_COLUMN, printing a newline if necessary,
1838 and updating *COLUMN. */ 2198 and updating *COLUMN. If ADD_LEFT_MARGIN, then print the (empty)
2199 left margin after any newline. */
1839 2200
1840 void 2201 void
1841 layout::move_to_column (int *column, int dest_column) 2202 layout::move_to_column (int *column, int dest_column, bool add_left_margin)
1842 { 2203 {
1843 /* Start a new line if we need to. */ 2204 /* Start a new line if we need to. */
1844 if (*column > dest_column) 2205 if (*column > dest_column)
1845 { 2206 {
1846 print_newline (); 2207 print_newline ();
1847 *column = 0; 2208 if (add_left_margin)
2209 start_annotation_line ();
2210 *column = m_x_offset;
1848 } 2211 }
1849 2212
1850 while (*column < dest_column) 2213 while (*column < dest_column)
1851 { 2214 {
1852 pp_space (m_pp); 2215 pp_space (m_pp);
1861 layout::show_ruler (int max_column) const 2224 layout::show_ruler (int max_column) const
1862 { 2225 {
1863 /* Hundreds. */ 2226 /* Hundreds. */
1864 if (max_column > 99) 2227 if (max_column > 99)
1865 { 2228 {
2229 start_annotation_line ();
1866 pp_space (m_pp); 2230 pp_space (m_pp);
1867 for (int column = 1 + m_x_offset; column <= max_column; column++) 2231 for (int column = 1 + m_x_offset; column <= max_column; column++)
1868 if (0 == column % 10) 2232 if (column % 10 == 0)
1869 pp_character (m_pp, '0' + (column / 100) % 10); 2233 pp_character (m_pp, '0' + (column / 100) % 10);
1870 else 2234 else
1871 pp_space (m_pp); 2235 pp_space (m_pp);
1872 pp_newline (m_pp); 2236 pp_newline (m_pp);
1873 } 2237 }
1874 2238
1875 /* Tens. */ 2239 /* Tens. */
2240 start_annotation_line ();
1876 pp_space (m_pp); 2241 pp_space (m_pp);
1877 for (int column = 1 + m_x_offset; column <= max_column; column++) 2242 for (int column = 1 + m_x_offset; column <= max_column; column++)
1878 if (0 == column % 10) 2243 if (column % 10 == 0)
1879 pp_character (m_pp, '0' + (column / 10) % 10); 2244 pp_character (m_pp, '0' + (column / 10) % 10);
1880 else 2245 else
1881 pp_space (m_pp); 2246 pp_space (m_pp);
1882 pp_newline (m_pp); 2247 pp_newline (m_pp);
1883 2248
1884 /* Units. */ 2249 /* Units. */
2250 start_annotation_line ();
1885 pp_space (m_pp); 2251 pp_space (m_pp);
1886 for (int column = 1 + m_x_offset; column <= max_column; column++) 2252 for (int column = 1 + m_x_offset; column <= max_column; column++)
1887 pp_character (m_pp, '0' + (column % 10)); 2253 pp_character (m_pp, '0' + (column % 10));
1888 pp_newline (m_pp); 2254 pp_newline (m_pp);
1889 } 2255 }
1891 /* Print leading fix-its (for new lines inserted before the source line) 2257 /* Print leading fix-its (for new lines inserted before the source line)
1892 then the source line, followed by an annotation line 2258 then the source line, followed by an annotation line
1893 consisting of any caret/underlines, then any fixits. 2259 consisting of any caret/underlines, then any fixits.
1894 If the source line can't be read, print nothing. */ 2260 If the source line can't be read, print nothing. */
1895 void 2261 void
1896 layout::print_line (int row) 2262 layout::print_line (linenum_type row)
1897 { 2263 {
1898 int line_width; 2264 char_span line = location_get_source_line (m_exploc.file, row);
1899 const char *line = location_get_source_line (m_exploc.file, row,
1900 &line_width);
1901 if (!line) 2265 if (!line)
1902 return; 2266 return;
1903 2267
1904 line_bounds lbounds; 2268 line_bounds lbounds;
1905 print_leading_fixits (row); 2269 print_leading_fixits (row);
1906 print_source_line (row, line, line_width, &lbounds); 2270 print_source_line (row, line.get_buffer (), line.length (), &lbounds);
1907 if (should_print_annotation_line_p (row)) 2271 if (should_print_annotation_line_p (row))
1908 print_annotation_line (row, lbounds); 2272 print_annotation_line (row, lbounds);
2273 if (m_show_labels_p)
2274 print_any_labels (row);
1909 print_trailing_fixits (row); 2275 print_trailing_fixits (row);
1910 } 2276 }
1911 2277
1912 } /* End of anonymous namespace. */ 2278 } /* End of anonymous namespace. */
1913 2279
1923 filtering it to the current line spans within a temporary 2289 filtering it to the current line spans within a temporary
1924 layout instance. */ 2290 layout instance. */
1925 layout layout (global_dc, this, DK_ERROR); 2291 layout layout (global_dc, this, DK_ERROR);
1926 location_range loc_range; 2292 location_range loc_range;
1927 loc_range.m_loc = loc; 2293 loc_range.m_loc = loc;
1928 loc_range.m_show_caret_p = false; 2294 loc_range.m_range_display_kind = SHOW_RANGE_WITHOUT_CARET;
1929 if (!layout.maybe_add_location_range (&loc_range, true)) 2295 if (!layout.maybe_add_location_range (&loc_range, 0, true))
1930 return false; 2296 return false;
1931 2297
1932 add_range (loc, false); 2298 add_range (loc);
1933 return true; 2299 return true;
1934 } 2300 }
1935 2301
1936 /* Print the physical source code corresponding to the location of 2302 /* Print the physical source code corresponding to the location of
1937 this diagnostic, with additional annotations. */ 2303 this diagnostic, with additional annotations. */
1958 && richloc->get_num_fixit_hints () == 0) 2324 && richloc->get_num_fixit_hints () == 0)
1959 return; 2325 return;
1960 2326
1961 context->last_location = loc; 2327 context->last_location = loc;
1962 2328
1963 const char *saved_prefix = pp_get_prefix (context->printer); 2329 char *saved_prefix = pp_take_prefix (context->printer);
1964 pp_set_prefix (context->printer, NULL); 2330 pp_set_prefix (context->printer, NULL);
1965 2331
1966 layout layout (context, richloc, diagnostic_kind); 2332 layout layout (context, richloc, diagnostic_kind);
1967 for (int line_span_idx = 0; line_span_idx < layout.get_num_line_spans (); 2333 for (int line_span_idx = 0; line_span_idx < layout.get_num_line_spans ();
1968 line_span_idx++) 2334 line_span_idx++)
1969 { 2335 {
1970 const line_span *line_span = layout.get_line_span (line_span_idx); 2336 const line_span *line_span = layout.get_line_span (line_span_idx);
1971 if (layout.print_heading_for_line_span_index_p (line_span_idx)) 2337 if (context->show_line_numbers_p)
1972 { 2338 {
1973 expanded_location exploc = layout.get_expanded_location (line_span); 2339 /* With line numbers, we should show whenever the line-numbering
1974 context->start_span (context, exploc); 2340 "jumps". */
2341 if (line_span_idx > 0)
2342 layout.print_gap_in_line_numbering ();
1975 } 2343 }
1976 int last_line = line_span->get_last_line (); 2344 else
1977 for (int row = line_span->get_first_line (); row <= last_line; row++) 2345 {
2346 /* Without line numbers, we print headings for some line spans. */
2347 if (layout.print_heading_for_line_span_index_p (line_span_idx))
2348 {
2349 expanded_location exploc
2350 = layout.get_expanded_location (line_span);
2351 context->start_span (context, exploc);
2352 }
2353 }
2354 linenum_type last_line = line_span->get_last_line ();
2355 for (linenum_type row = line_span->get_first_line ();
2356 row <= last_line; row++)
1978 layout.print_line (row); 2357 layout.print_line (row);
1979 } 2358 }
1980 2359
1981 pp_set_prefix (context->printer, saved_prefix); 2360 pp_set_prefix (context->printer, saved_prefix);
1982 } 2361 }
1984 #if CHECKING_P 2363 #if CHECKING_P
1985 2364
1986 namespace selftest { 2365 namespace selftest {
1987 2366
1988 /* Selftests for diagnostic_show_locus. */ 2367 /* Selftests for diagnostic_show_locus. */
1989
1990 /* Convenience subclass of diagnostic_context for testing
1991 diagnostic_show_locus. */
1992
1993 class test_diagnostic_context : public diagnostic_context
1994 {
1995 public:
1996 test_diagnostic_context ()
1997 {
1998 diagnostic_initialize (this, 0);
1999 show_caret = true;
2000 show_column = true;
2001 start_span = start_span_cb;
2002 }
2003 ~test_diagnostic_context ()
2004 {
2005 diagnostic_finish (this);
2006 }
2007
2008 /* Implementation of diagnostic_start_span_fn, hiding the
2009 real filename (to avoid printing the names of tempfiles). */
2010 static void
2011 start_span_cb (diagnostic_context *context, expanded_location exploc)
2012 {
2013 exploc.file = "FILENAME";
2014 default_diagnostic_start_span_fn (context, exploc);
2015 }
2016 };
2017 2368
2018 /* Verify that diagnostic_show_locus works sanely on UNKNOWN_LOCATION. */ 2369 /* Verify that diagnostic_show_locus works sanely on UNKNOWN_LOCATION. */
2019 2370
2020 static void 2371 static void
2021 test_diagnostic_show_locus_unknown_location () 2372 test_diagnostic_show_locus_unknown_location ()
2092 linemap_position_for_column (line_table, 11), 2443 linemap_position_for_column (line_table, 11),
2093 linemap_position_for_column (line_table, 15)); 2444 linemap_position_for_column (line_table, 15));
2094 dc.caret_chars[2] = 'C'; 2445 dc.caret_chars[2] = 'C';
2095 2446
2096 rich_location richloc (line_table, foo); 2447 rich_location richloc (line_table, foo);
2097 richloc.add_range (bar, true); 2448 richloc.add_range (bar, SHOW_RANGE_WITH_CARET);
2098 richloc.add_range (field, true); 2449 richloc.add_range (field, SHOW_RANGE_WITH_CARET);
2099 diagnostic_show_locus (&dc, &richloc, DK_ERROR); 2450 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
2100 ASSERT_STREQ ("\n" 2451 ASSERT_STREQ ("\n"
2101 " foo = bar.field;\n" 2452 " foo = bar.field;\n"
2102 " ~A~ ~B~ ~~C~~\n", 2453 " ~A~ ~B~ ~~C~~\n",
2103 pp_formatted_text (dc.printer)); 2454 pp_formatted_text (dc.printer));
2214 location_t equals = linemap_position_for_column (line_table, 5); 2565 location_t equals = linemap_position_for_column (line_table, 5);
2215 location_t start = linemap_position_for_column (line_table, 11); 2566 location_t start = linemap_position_for_column (line_table, 11);
2216 location_t finish = linemap_position_for_column (line_table, 15); 2567 location_t finish = linemap_position_for_column (line_table, 15);
2217 rich_location richloc (line_table, equals); 2568 rich_location richloc (line_table, equals);
2218 location_t field = make_location (start, start, finish); 2569 location_t field = make_location (start, start, finish);
2219 richloc.add_range (field, false); 2570 richloc.add_range (field);
2220 richloc.add_fixit_replace (field, "m_field"); 2571 richloc.add_fixit_replace (field, "m_field");
2221 diagnostic_show_locus (&dc, &richloc, DK_ERROR); 2572 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
2222 /* The replacement range is indicated in the annotation line, 2573 /* The replacement range is indicated in the annotation line,
2223 so it shouldn't be indicated via an additional underline. */ 2574 so it shouldn't be indicated via an additional underline. */
2224 ASSERT_STREQ ("\n" 2575 ASSERT_STREQ ("\n"
2337 " ^\n" 2688 " ^\n"
2338 "a a a a a a a a a a a a a a a a a a a\n", 2689 "a a a a a a a a a a a a a a a a a a a\n",
2339 pp_formatted_text (dc.printer)); 2690 pp_formatted_text (dc.printer));
2340 } 2691 }
2341 2692
2693 /* Test of labeling the ranges within a rich_location. */
2694
2695 static void
2696 test_one_liner_labels ()
2697 {
2698 location_t foo
2699 = make_location (linemap_position_for_column (line_table, 1),
2700 linemap_position_for_column (line_table, 1),
2701 linemap_position_for_column (line_table, 3));
2702 location_t bar
2703 = make_location (linemap_position_for_column (line_table, 7),
2704 linemap_position_for_column (line_table, 7),
2705 linemap_position_for_column (line_table, 9));
2706 location_t field
2707 = make_location (linemap_position_for_column (line_table, 11),
2708 linemap_position_for_column (line_table, 11),
2709 linemap_position_for_column (line_table, 15));
2710
2711 /* Example where all the labels fit on one line. */
2712 {
2713 text_range_label label0 ("0");
2714 text_range_label label1 ("1");
2715 text_range_label label2 ("2");
2716 gcc_rich_location richloc (foo, &label0);
2717 richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
2718 richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
2719
2720 {
2721 test_diagnostic_context dc;
2722 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
2723 ASSERT_STREQ ("\n"
2724 " foo = bar.field;\n"
2725 " ^~~ ~~~ ~~~~~\n"
2726 " | | |\n"
2727 " 0 1 2\n",
2728 pp_formatted_text (dc.printer));
2729 }
2730
2731 /* Verify that we can disable label-printing. */
2732 {
2733 test_diagnostic_context dc;
2734 dc.show_labels_p = false;
2735 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
2736 ASSERT_STREQ ("\n"
2737 " foo = bar.field;\n"
2738 " ^~~ ~~~ ~~~~~\n",
2739 pp_formatted_text (dc.printer));
2740 }
2741 }
2742
2743 /* Example where the labels need extra lines. */
2744 {
2745 text_range_label label0 ("label 0");
2746 text_range_label label1 ("label 1");
2747 text_range_label label2 ("label 2");
2748 gcc_rich_location richloc (foo, &label0);
2749 richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
2750 richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
2751
2752 test_diagnostic_context dc;
2753 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
2754 ASSERT_STREQ ("\n"
2755 " foo = bar.field;\n"
2756 " ^~~ ~~~ ~~~~~\n"
2757 " | | |\n"
2758 " | | label 2\n"
2759 " | label 1\n"
2760 " label 0\n",
2761 pp_formatted_text (dc.printer));
2762 }
2763
2764 /* Example of boundary conditions: label 0 and 1 have just enough clearance,
2765 but label 1 just touches label 2. */
2766 {
2767 text_range_label label0 ("aaaaa");
2768 text_range_label label1 ("bbbb");
2769 text_range_label label2 ("c");
2770 gcc_rich_location richloc (foo, &label0);
2771 richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
2772 richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
2773
2774 test_diagnostic_context dc;
2775 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
2776 ASSERT_STREQ ("\n"
2777 " foo = bar.field;\n"
2778 " ^~~ ~~~ ~~~~~\n"
2779 " | | |\n"
2780 " | | c\n"
2781 " aaaaa bbbb\n",
2782 pp_formatted_text (dc.printer));
2783 }
2784
2785 /* Example of out-of-order ranges (thus requiring a sort). */
2786 {
2787 text_range_label label0 ("0");
2788 text_range_label label1 ("1");
2789 text_range_label label2 ("2");
2790 gcc_rich_location richloc (field, &label0);
2791 richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
2792 richloc.add_range (foo, SHOW_RANGE_WITHOUT_CARET, &label2);
2793
2794 test_diagnostic_context dc;
2795 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
2796 ASSERT_STREQ ("\n"
2797 " foo = bar.field;\n"
2798 " ~~~ ~~~ ^~~~~\n"
2799 " | | |\n"
2800 " 2 1 0\n",
2801 pp_formatted_text (dc.printer));
2802 }
2803
2804 /* Ensure we don't ICE if multiple ranges with labels are on
2805 the same point. */
2806 {
2807 text_range_label label0 ("label 0");
2808 text_range_label label1 ("label 1");
2809 text_range_label label2 ("label 2");
2810 gcc_rich_location richloc (bar, &label0);
2811 richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
2812 richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label2);
2813
2814 test_diagnostic_context dc;
2815 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
2816 ASSERT_STREQ ("\n"
2817 " foo = bar.field;\n"
2818 " ^~~\n"
2819 " |\n"
2820 " label 2\n"
2821 " label 1\n"
2822 " label 0\n",
2823 pp_formatted_text (dc.printer));
2824 }
2825
2826 /* Verify that a NULL result from range_label::get_text is
2827 handled gracefully. */
2828 {
2829 text_range_label label (NULL);
2830 gcc_rich_location richloc (bar, &label);
2831
2832 test_diagnostic_context dc;
2833 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
2834 ASSERT_STREQ ("\n"
2835 " foo = bar.field;\n"
2836 " ^~~\n",
2837 pp_formatted_text (dc.printer));
2838 }
2839
2840 /* TODO: example of formatted printing (needs to be in
2841 gcc-rich-location.c due to Makefile.in issues). */
2842 }
2843
2342 /* Run the various one-liner tests. */ 2844 /* Run the various one-liner tests. */
2343 2845
2344 static void 2846 static void
2345 test_diagnostic_show_locus_one_liner (const line_table_case &case_) 2847 test_diagnostic_show_locus_one_liner (const line_table_case &case_)
2346 { 2848 {
2373 test_one_liner_fixit_replace_non_equal_range (); 2875 test_one_liner_fixit_replace_non_equal_range ();
2374 test_one_liner_fixit_replace_equal_secondary_range (); 2876 test_one_liner_fixit_replace_equal_secondary_range ();
2375 test_one_liner_fixit_validation_adhoc_locations (); 2877 test_one_liner_fixit_validation_adhoc_locations ();
2376 test_one_liner_many_fixits_1 (); 2878 test_one_liner_many_fixits_1 ();
2377 test_one_liner_many_fixits_2 (); 2879 test_one_liner_many_fixits_2 ();
2880 test_one_liner_labels ();
2378 } 2881 }
2379 2882
2380 /* Verify that gcc_rich_location::add_location_if_nearby works. */ 2883 /* Verify that gcc_rich_location::add_location_if_nearby works. */
2381 2884
2382 static void 2885 static void
2515 " : 0.0};\n" 3018 " : 0.0};\n"
2516 " ^\n" 3019 " ^\n"
2517 " =\n", 3020 " =\n",
2518 pp_formatted_text (dc.printer)); 3021 pp_formatted_text (dc.printer));
2519 } 3022 }
3023
3024 /* As above, but verify the behavior of multiple line spans
3025 with line-numbering enabled. */
3026 {
3027 const location_t y
3028 = linemap_position_for_line_and_column (line_table, ord_map, 3, 24);
3029 const location_t colon
3030 = linemap_position_for_line_and_column (line_table, ord_map, 6, 25);
3031 rich_location richloc (line_table, colon);
3032 richloc.add_fixit_insert_before (y, ".");
3033 richloc.add_fixit_replace (colon, "=");
3034 test_diagnostic_context dc;
3035 dc.show_line_numbers_p = true;
3036 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
3037 ASSERT_STREQ ("\n"
3038 " 3 | y\n"
3039 " | .\n"
3040 "......\n"
3041 " 6 | : 0.0};\n"
3042 " | ^\n"
3043 " | =\n",
3044 pp_formatted_text (dc.printer));
3045 }
2520 } 3046 }
2521 3047
2522 3048
2523 /* Verify that fix-it hints are appropriately consolidated. 3049 /* Verify that fix-it hints are appropriately consolidated.
2524 3050
2984 /* Add a "break;" on a line by itself before line 3 i.e. before 3510 /* Add a "break;" on a line by itself before line 3 i.e. before
2985 column 1 of line 3. */ 3511 column 1 of line 3. */
2986 { 3512 {
2987 rich_location richloc (line_table, case_loc); 3513 rich_location richloc (line_table, case_loc);
2988 richloc.add_fixit_insert_before (line_start, " break;\n"); 3514 richloc.add_fixit_insert_before (line_start, " break;\n");
2989 test_diagnostic_context dc; 3515
2990 diagnostic_show_locus (&dc, &richloc, DK_ERROR); 3516 /* Without line numbers. */
2991 ASSERT_STREQ ("\n" 3517 {
2992 "+ break;\n" 3518 test_diagnostic_context dc;
2993 " case 'b':\n" 3519 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
2994 " ^~~~~~~~~\n", 3520 ASSERT_STREQ ("\n"
2995 pp_formatted_text (dc.printer)); 3521 " x = a;\n"
3522 "+ break;\n"
3523 " case 'b':\n"
3524 " ^~~~~~~~~\n",
3525 pp_formatted_text (dc.printer));
3526 }
3527
3528 /* With line numbers. */
3529 {
3530 test_diagnostic_context dc;
3531 dc.show_line_numbers_p = true;
3532 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
3533 ASSERT_STREQ ("\n"
3534 " 2 | x = a;\n"
3535 " +++ |+ break;\n"
3536 " 3 | case 'b':\n"
3537 " | ^~~~~~~~~\n",
3538 pp_formatted_text (dc.printer));
3539 }
2996 } 3540 }
2997 3541
2998 /* Verify that attempts to add text with a newline fail when the 3542 /* Verify that attempts to add text with a newline fail when the
2999 insertion point is *not* at the start of a line. */ 3543 insertion point is *not* at the start of a line. */
3000 { 3544 {
3047 richloc.add_fixit_insert_before (file_start, "#include <stdio.h>\n"); 3591 richloc.add_fixit_insert_before (file_start, "#include <stdio.h>\n");
3048 3592
3049 if (putchar_finish > LINE_MAP_MAX_LOCATION_WITH_COLS) 3593 if (putchar_finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
3050 return; 3594 return;
3051 3595
3052 test_diagnostic_context dc; 3596 {
3053 diagnostic_show_locus (&dc, &richloc, DK_ERROR); 3597 test_diagnostic_context dc;
3054 ASSERT_STREQ ("\n" 3598 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
3055 "FILENAME:1:1:\n" 3599 ASSERT_STREQ ("\n"
3056 "+#include <stdio.h>\n" 3600 "FILENAME:1:1:\n"
3057 " test (int ch)\n" 3601 "+#include <stdio.h>\n"
3058 "FILENAME:3:2:\n" 3602 " test (int ch)\n"
3059 " putchar (ch);\n" 3603 "FILENAME:3:2:\n"
3060 " ^~~~~~~\n", 3604 " putchar (ch);\n"
3061 pp_formatted_text (dc.printer)); 3605 " ^~~~~~~\n",
3606 pp_formatted_text (dc.printer));
3607 }
3608
3609 /* With line-numbering, the line spans are close enough to be
3610 consolidated, since it makes little sense to skip line 2. */
3611 {
3612 test_diagnostic_context dc;
3613 dc.show_line_numbers_p = true;
3614 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
3615 ASSERT_STREQ ("\n"
3616 " +++ |+#include <stdio.h>\n"
3617 " 1 | test (int ch)\n"
3618 " 2 | {\n"
3619 " 3 | putchar (ch);\n"
3620 " | ^~~~~~~\n",
3621 pp_formatted_text (dc.printer));
3622 }
3062 } 3623 }
3063 3624
3064 /* Replacement fix-it hint containing a newline. 3625 /* Replacement fix-it hint containing a newline.
3065 This will fail, as newlines are only supported when inserting at the 3626 This will fail, as newlines are only supported when inserting at the
3066 beginning of a line. */ 3627 beginning of a line. */
3146 " );\n" 3707 " );\n"
3147 " ~ \n", 3708 " ~ \n",
3148 pp_formatted_text (dc.printer)); 3709 pp_formatted_text (dc.printer));
3149 } 3710 }
3150 3711
3712 /* Verify that line numbers are correctly printed for the case of
3713 a multiline range in which the width of the line numbers changes
3714 (e.g. from "9" to "10"). */
3715
3716 static void
3717 test_line_numbers_multiline_range ()
3718 {
3719 /* Create a tempfile and write some text to it. */
3720 pretty_printer pp;
3721 for (int i = 0; i < 20; i++)
3722 /* .........0000000001111111.
3723 .............1234567890123456. */
3724 pp_printf (&pp, "this is line %i\n", i + 1);
3725 temp_source_file tmp (SELFTEST_LOCATION, ".txt", pp_formatted_text (&pp));
3726 line_table_test ltt;
3727
3728 const line_map_ordinary *ord_map = linemap_check_ordinary
3729 (linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0));
3730 linemap_line_start (line_table, 1, 100);
3731
3732 /* Create a multi-line location, starting at the "line" of line 9, with
3733 a caret on the "is" of line 10, finishing on the "this" line 11. */
3734
3735 location_t start
3736 = linemap_position_for_line_and_column (line_table, ord_map, 9, 9);
3737 location_t caret
3738 = linemap_position_for_line_and_column (line_table, ord_map, 10, 6);
3739 location_t finish
3740 = linemap_position_for_line_and_column (line_table, ord_map, 11, 4);
3741 location_t loc = make_location (caret, start, finish);
3742
3743 test_diagnostic_context dc;
3744 dc.show_line_numbers_p = true;
3745 dc.min_margin_width = 0;
3746 gcc_rich_location richloc (loc);
3747 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
3748 ASSERT_STREQ ("\n"
3749 " 9 | this is line 9\n"
3750 " | ~~~~~~\n"
3751 "10 | this is line 10\n"
3752 " | ~~~~~^~~~~~~~~~\n"
3753 "11 | this is line 11\n"
3754 " | ~~~~ \n",
3755 pp_formatted_text (dc.printer));
3756 }
3757
3151 /* Run all of the selftests within this file. */ 3758 /* Run all of the selftests within this file. */
3152 3759
3153 void 3760 void
3154 diagnostic_show_locus_c_tests () 3761 diagnostic_show_locus_c_tests ()
3155 { 3762 {
3763 test_line_span ();
3764 test_num_digits ();
3765
3156 test_layout_range_for_single_point (); 3766 test_layout_range_for_single_point ();
3157 test_layout_range_for_single_line (); 3767 test_layout_range_for_single_line ();
3158 test_layout_range_for_multiple_lines (); 3768 test_layout_range_for_multiple_lines ();
3159 3769
3160 test_get_line_width_without_trailing_whitespace (); 3770 test_get_line_width_without_trailing_whitespace ();
3169 for_each_line_table_case (test_overlapped_fixit_printing_2); 3779 for_each_line_table_case (test_overlapped_fixit_printing_2);
3170 for_each_line_table_case (test_fixit_insert_containing_newline); 3780 for_each_line_table_case (test_fixit_insert_containing_newline);
3171 for_each_line_table_case (test_fixit_insert_containing_newline_2); 3781 for_each_line_table_case (test_fixit_insert_containing_newline_2);
3172 for_each_line_table_case (test_fixit_replace_containing_newline); 3782 for_each_line_table_case (test_fixit_replace_containing_newline);
3173 for_each_line_table_case (test_fixit_deletion_affecting_newline); 3783 for_each_line_table_case (test_fixit_deletion_affecting_newline);
3784
3785 test_line_numbers_multiline_range ();
3174 } 3786 }
3175 3787
3176 } // namespace selftest 3788 } // namespace selftest
3177 3789
3178 #endif /* #if CHECKING_P */ 3790 #endif /* #if CHECKING_P */