Mercurial > hg > CbC > CbC_gcc
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 */ |