1 /* Diagnostic subroutines for printing source-code
2 Copyright (C) 1999-2019 Free Software Foundation, Inc.
3 Contributed by Gabriel Dos Reis <gdr@codesourcery.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
27 #include "backtrace.h"
28 #include "diagnostic.h"
29 #include "diagnostic-color.h"
30 #include "gcc-rich-location.h"
32 #include "selftest-diagnostic.h"
38 #ifdef GWINSZ_IN_SYS_IOCTL
39 # include <sys/ioctl.h>
42 /* Disable warnings about quoting issues in the pp_xxx calls below
43 that (intentionally) don't follow GCC diagnostic conventions. */
45 # pragma GCC diagnostic push
46 # pragma GCC diagnostic ignored "-Wformat-diag"
49 /* Classes for rendering source code and diagnostics, within an
51 The work is done by "class layout", which embeds and uses
52 "class colorizer" and "class layout_range" to get things done. */
56 /* The state at a given point of the source code, assuming that we're
57 in a range: which range are we in, and whether we should draw a caret at
66 /* A class to inject colorization codes when printing the diagnostic locus.
68 It has one kind of colorization for each of:
70 - range 0 (the "primary location")
74 The class caches the lookup of the color codes for the above.
76 The class also has responsibility for tracking which of the above is
77 active, filtering out unnecessary changes. This allows
78 layout::print_source_line and layout::print_annotation_line
79 to simply request a colorization code for *every* character they print,
80 via this class, and have the filtering be done for them here. */
85 colorizer (diagnostic_context
*context
,
86 diagnostic_t diagnostic_kind
);
89 void set_range (int range_idx
) { set_state (range_idx
); }
90 void set_normal_text () { set_state (STATE_NORMAL_TEXT
); }
91 void set_fixit_insert () { set_state (STATE_FIXIT_INSERT
); }
92 void set_fixit_delete () { set_state (STATE_FIXIT_DELETE
); }
95 void set_state (int state
);
96 void begin_state (int state
);
97 void finish_state (int state
);
98 const char *get_color_by_name (const char *);
101 static const int STATE_NORMAL_TEXT
= -1;
102 static const int STATE_FIXIT_INSERT
= -2;
103 static const int STATE_FIXIT_DELETE
= -3;
105 diagnostic_context
*m_context
;
106 diagnostic_t m_diagnostic_kind
;
108 const char *m_range1
;
109 const char *m_range2
;
110 const char *m_fixit_insert
;
111 const char *m_fixit_delete
;
112 const char *m_stop_color
;
115 /* A point within a layout_range; similar to an expanded_location,
116 but after filtering on file. */
121 layout_point (const expanded_location
&exploc
)
122 : m_line (exploc
.line
),
123 m_column (exploc
.column
) {}
129 /* A class for use by "class layout" below: a filtered location_range. */
134 layout_range (const expanded_location
*start_exploc
,
135 const expanded_location
*finish_exploc
,
136 enum range_display_kind range_display_kind
,
137 const expanded_location
*caret_exploc
,
138 unsigned original_idx
,
139 const range_label
*label
);
141 bool contains_point (linenum_type row
, int column
) const;
142 bool intersects_line_p (linenum_type row
) const;
144 layout_point m_start
;
145 layout_point m_finish
;
146 enum range_display_kind m_range_display_kind
;
147 layout_point m_caret
;
148 unsigned m_original_idx
;
149 const range_label
*m_label
;
152 /* A struct for use by layout::print_source_line for telling
153 layout::print_annotation_line the extents of the source line that
154 it printed, so that underlines can be clipped appropriately. */
162 /* A range of contiguous source lines within a layout (e.g. "lines 5-10"
163 or "line 23"). During the layout ctor, layout::calculate_line_spans
164 splits the pertinent source lines into a list of disjoint line_span
165 instances (e.g. lines 5-10, lines 15-20, line 23). */
169 line_span (linenum_type first_line
, linenum_type last_line
)
170 : m_first_line (first_line
), m_last_line (last_line
)
172 gcc_assert (first_line
<= last_line
);
174 linenum_type
get_first_line () const { return m_first_line
; }
175 linenum_type
get_last_line () const { return m_last_line
; }
177 bool contains_line_p (linenum_type line
) const
179 return line
>= m_first_line
&& line
<= m_last_line
;
182 static int comparator (const void *p1
, const void *p2
)
184 const line_span
*ls1
= (const line_span
*)p1
;
185 const line_span
*ls2
= (const line_span
*)p2
;
186 int first_line_cmp
= compare (ls1
->m_first_line
, ls2
->m_first_line
);
188 return first_line_cmp
;
189 return compare (ls1
->m_last_line
, ls2
->m_last_line
);
192 linenum_type m_first_line
;
193 linenum_type m_last_line
;
198 /* Selftests for line_span. */
203 line_span
line_one (1, 1);
204 ASSERT_EQ (1, line_one
.get_first_line ());
205 ASSERT_EQ (1, line_one
.get_last_line ());
206 ASSERT_FALSE (line_one
.contains_line_p (0));
207 ASSERT_TRUE (line_one
.contains_line_p (1));
208 ASSERT_FALSE (line_one
.contains_line_p (2));
210 line_span
lines_1_to_3 (1, 3);
211 ASSERT_EQ (1, lines_1_to_3
.get_first_line ());
212 ASSERT_EQ (3, lines_1_to_3
.get_last_line ());
213 ASSERT_TRUE (lines_1_to_3
.contains_line_p (1));
214 ASSERT_TRUE (lines_1_to_3
.contains_line_p (3));
216 ASSERT_EQ (0, line_span::comparator (&line_one
, &line_one
));
217 ASSERT_GT (line_span::comparator (&lines_1_to_3
, &line_one
), 0);
218 ASSERT_LT (line_span::comparator (&line_one
, &lines_1_to_3
), 0);
220 /* A linenum > 2^31. */
221 const linenum_type LARGEST_LINE
= 0xffffffff;
222 line_span
largest_line (LARGEST_LINE
, LARGEST_LINE
);
223 ASSERT_EQ (LARGEST_LINE
, largest_line
.get_first_line ());
224 ASSERT_EQ (LARGEST_LINE
, largest_line
.get_last_line ());
226 ASSERT_GT (line_span::comparator (&largest_line
, &line_one
), 0);
227 ASSERT_LT (line_span::comparator (&line_one
, &largest_line
), 0);
230 #endif /* #if CHECKING_P */
232 /* A class to control the overall layout when printing a diagnostic.
234 The layout is determined within the constructor.
235 It is then printed by repeatedly calling the "print_source_line",
236 "print_annotation_line" and "print_any_fixits" methods.
238 We assume we have disjoint ranges. */
243 layout (diagnostic_context
*context
,
244 rich_location
*richloc
,
245 diagnostic_t diagnostic_kind
);
247 bool maybe_add_location_range (const location_range
*loc_range
,
248 unsigned original_idx
,
249 bool restrict_to_current_line_spans
);
251 int get_num_line_spans () const { return m_line_spans
.length (); }
252 const line_span
*get_line_span (int idx
) const { return &m_line_spans
[idx
]; }
254 void print_gap_in_line_numbering ();
255 bool print_heading_for_line_span_index_p (int line_span_idx
) const;
257 expanded_location
get_expanded_location (const line_span
*) const;
259 void print_line (linenum_type row
);
262 bool will_show_line_p (linenum_type row
) const;
263 void print_leading_fixits (linenum_type row
);
264 void print_source_line (linenum_type row
, const char *line
, int line_width
,
265 line_bounds
*lbounds_out
);
266 bool should_print_annotation_line_p (linenum_type row
) const;
267 void start_annotation_line (char margin_char
= ' ') const;
268 void print_annotation_line (linenum_type row
, const line_bounds lbounds
);
269 void print_any_labels (linenum_type row
);
270 void print_trailing_fixits (linenum_type row
);
272 bool annotation_line_showed_range_p (linenum_type line
, int start_column
,
273 int finish_column
) const;
274 void show_ruler (int max_column
) const;
276 bool validate_fixit_hint_p (const fixit_hint
*hint
);
278 void calculate_line_spans ();
280 void print_newline ();
283 get_state_at_point (/* Inputs. */
284 linenum_type row
, int column
,
285 int first_non_ws
, int last_non_ws
,
287 point_state
*out_state
);
290 get_x_bound_for_row (linenum_type row
, int caret_column
,
294 move_to_column (int *column
, int dest_column
, bool add_left_margin
);
297 diagnostic_context
*m_context
;
298 pretty_printer
*m_pp
;
299 location_t m_primary_loc
;
300 expanded_location m_exploc
;
301 colorizer m_colorizer
;
302 bool m_colorize_source_p
;
303 bool m_show_labels_p
;
304 bool m_show_line_numbers_p
;
305 auto_vec
<layout_range
> m_layout_ranges
;
306 auto_vec
<const fixit_hint
*> m_fixit_hints
;
307 auto_vec
<line_span
> m_line_spans
;
312 /* Implementation of "class colorizer". */
314 /* The constructor for "colorizer". Lookup and store color codes for the
315 different kinds of things we might need to print. */
317 colorizer::colorizer (diagnostic_context
*context
,
318 diagnostic_t diagnostic_kind
) :
320 m_diagnostic_kind (diagnostic_kind
),
321 m_current_state (STATE_NORMAL_TEXT
)
323 m_range1
= get_color_by_name ("range1");
324 m_range2
= get_color_by_name ("range2");
325 m_fixit_insert
= get_color_by_name ("fixit-insert");
326 m_fixit_delete
= get_color_by_name ("fixit-delete");
327 m_stop_color
= colorize_stop (pp_show_color (context
->printer
));
330 /* The destructor for "colorize". If colorization is on, print a code to
333 colorizer::~colorizer ()
335 finish_state (m_current_state
);
338 /* Update state, printing color codes if necessary if there's a state
342 colorizer::set_state (int new_state
)
344 if (m_current_state
!= new_state
)
346 finish_state (m_current_state
);
347 m_current_state
= new_state
;
348 begin_state (new_state
);
352 /* Turn on any colorization for STATE. */
355 colorizer::begin_state (int state
)
359 case STATE_NORMAL_TEXT
:
362 case STATE_FIXIT_INSERT
:
363 pp_string (m_context
->printer
, m_fixit_insert
);
366 case STATE_FIXIT_DELETE
:
367 pp_string (m_context
->printer
, m_fixit_delete
);
371 /* Make range 0 be the same color as the "kind" text
372 (error vs warning vs note). */
375 colorize_start (pp_show_color (m_context
->printer
),
376 diagnostic_get_color_for_kind (m_diagnostic_kind
)));
380 pp_string (m_context
->printer
, m_range1
);
384 pp_string (m_context
->printer
, m_range2
);
388 /* For ranges beyond 2, alternate between color 1 and color 2. */
390 gcc_assert (state
> 2);
391 pp_string (m_context
->printer
,
392 state
% 2 ? m_range1
: m_range2
);
398 /* Turn off any colorization for STATE. */
401 colorizer::finish_state (int state
)
403 if (state
!= STATE_NORMAL_TEXT
)
404 pp_string (m_context
->printer
, m_stop_color
);
407 /* Get the color code for NAME (or the empty string if
408 colorization is disabled). */
411 colorizer::get_color_by_name (const char *name
)
413 return colorize_start (pp_show_color (m_context
->printer
), name
);
416 /* Implementation of class layout_range. */
418 /* The constructor for class layout_range.
419 Initialize various layout_point fields from expanded_location
420 equivalents; we've already filtered on file. */
422 layout_range::layout_range (const expanded_location
*start_exploc
,
423 const expanded_location
*finish_exploc
,
424 enum range_display_kind range_display_kind
,
425 const expanded_location
*caret_exploc
,
426 unsigned original_idx
,
427 const range_label
*label
)
428 : m_start (*start_exploc
),
429 m_finish (*finish_exploc
),
430 m_range_display_kind (range_display_kind
),
431 m_caret (*caret_exploc
),
432 m_original_idx (original_idx
),
437 /* Is (column, row) within the given range?
438 We've already filtered on the file.
440 Ranges are closed (both limits are within the range).
442 Example A: a single-line range:
443 start: (col=22, line=2)
444 finish: (col=38, line=2)
446 |00000011111111112222222222333333333344444444444
447 |34567890123456789012345678901234567890123456789
448 --+-----------------------------------------------
449 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
450 02|bbbbbbbbbbbbbbbbbbbSwwwwwwwwwwwwwwwFaaaaaaaaaaa
451 03|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
453 Example B: a multiline range with
454 start: (col=14, line=3)
455 finish: (col=08, line=5)
457 |00000011111111112222222222333333333344444444444
458 |34567890123456789012345678901234567890123456789
459 --+-----------------------------------------------
460 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
461 02|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
462 03|bbbbbbbbbbbSwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
463 04|wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
464 05|wwwwwFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
465 06|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
466 --+-----------------------------------------------
469 - 'b' indicates a point *before* the range
470 - 'S' indicates the start of the range
471 - 'w' indicates a point within the range
472 - 'F' indicates the finish of the range (which is
474 - 'a' indicates a subsequent point *after* the range. */
477 layout_range::contains_point (linenum_type row
, int column
) const
479 gcc_assert (m_start
.m_line
<= m_finish
.m_line
);
480 /* ...but the equivalent isn't true for the columns;
481 consider example B in the comment above. */
483 if (row
< m_start
.m_line
)
484 /* Points before the first line of the range are
485 outside it (corresponding to line 01 in example A
486 and lines 01 and 02 in example B above). */
489 if (row
== m_start
.m_line
)
490 /* On same line as start of range (corresponding
491 to line 02 in example A and line 03 in example B). */
493 if (column
< m_start
.m_column
)
494 /* Points on the starting line of the range, but
495 before the column in which it begins. */
498 if (row
< m_finish
.m_line
)
499 /* This is a multiline range; the point
500 is within it (corresponds to line 03 in example B
501 from column 14 onwards) */
505 /* This is a single-line range. */
506 gcc_assert (row
== m_finish
.m_line
);
507 return column
<= m_finish
.m_column
;
511 /* The point is in a line beyond that containing the
512 start of the range: lines 03 onwards in example A,
513 and lines 04 onwards in example B. */
514 gcc_assert (row
> m_start
.m_line
);
516 if (row
> m_finish
.m_line
)
517 /* The point is beyond the final line of the range
518 (lines 03 onwards in example A, and lines 06 onwards
522 if (row
< m_finish
.m_line
)
524 /* The point is in a line that's fully within a multiline
525 range (e.g. line 04 in example B). */
526 gcc_assert (m_start
.m_line
< m_finish
.m_line
);
530 gcc_assert (row
== m_finish
.m_line
);
532 return column
<= m_finish
.m_column
;
535 /* Does this layout_range contain any part of line ROW? */
538 layout_range::intersects_line_p (linenum_type row
) const
540 gcc_assert (m_start
.m_line
<= m_finish
.m_line
);
541 if (row
< m_start
.m_line
)
543 if (row
> m_finish
.m_line
)
550 /* A helper function for testing layout_range. */
553 make_range (int start_line
, int start_col
, int end_line
, int end_col
)
555 const expanded_location start_exploc
556 = {"test.c", start_line
, start_col
, NULL
, false};
557 const expanded_location finish_exploc
558 = {"test.c", end_line
, end_col
, NULL
, false};
559 return layout_range (&start_exploc
, &finish_exploc
, SHOW_RANGE_WITHOUT_CARET
,
560 &start_exploc
, 0, NULL
);
563 /* Selftests for layout_range::contains_point and
564 layout_range::intersects_line_p. */
566 /* Selftest for layout_range, where the layout_range
567 is a range with start==end i.e. a single point. */
570 test_layout_range_for_single_point ()
572 layout_range point
= make_range (7, 10, 7, 10);
574 /* Tests for layout_range::contains_point. */
576 /* Before the line. */
577 ASSERT_FALSE (point
.contains_point (6, 1));
579 /* On the line, but before start. */
580 ASSERT_FALSE (point
.contains_point (7, 9));
583 ASSERT_TRUE (point
.contains_point (7, 10));
585 /* On the line, after the point. */
586 ASSERT_FALSE (point
.contains_point (7, 11));
588 /* After the line. */
589 ASSERT_FALSE (point
.contains_point (8, 1));
591 /* Tests for layout_range::intersects_line_p. */
592 ASSERT_FALSE (point
.intersects_line_p (6));
593 ASSERT_TRUE (point
.intersects_line_p (7));
594 ASSERT_FALSE (point
.intersects_line_p (8));
597 /* Selftest for layout_range, where the layout_range
598 is the single-line range shown as "Example A" above. */
601 test_layout_range_for_single_line ()
603 layout_range example_a
= make_range (2, 22, 2, 38);
605 /* Tests for layout_range::contains_point. */
607 /* Before the line. */
608 ASSERT_FALSE (example_a
.contains_point (1, 1));
610 /* On the line, but before start. */
611 ASSERT_FALSE (example_a
.contains_point (2, 21));
613 /* On the line, at the start. */
614 ASSERT_TRUE (example_a
.contains_point (2, 22));
616 /* On the line, within the range. */
617 ASSERT_TRUE (example_a
.contains_point (2, 23));
619 /* On the line, at the end. */
620 ASSERT_TRUE (example_a
.contains_point (2, 38));
622 /* On the line, after the end. */
623 ASSERT_FALSE (example_a
.contains_point (2, 39));
625 /* After the line. */
626 ASSERT_FALSE (example_a
.contains_point (2, 39));
628 /* Tests for layout_range::intersects_line_p. */
629 ASSERT_FALSE (example_a
.intersects_line_p (1));
630 ASSERT_TRUE (example_a
.intersects_line_p (2));
631 ASSERT_FALSE (example_a
.intersects_line_p (3));
634 /* Selftest for layout_range, where the layout_range
635 is the multi-line range shown as "Example B" above. */
638 test_layout_range_for_multiple_lines ()
640 layout_range example_b
= make_range (3, 14, 5, 8);
642 /* Tests for layout_range::contains_point. */
644 /* Before first line. */
645 ASSERT_FALSE (example_b
.contains_point (1, 1));
647 /* On the first line, but before start. */
648 ASSERT_FALSE (example_b
.contains_point (3, 13));
651 ASSERT_TRUE (example_b
.contains_point (3, 14));
653 /* On the first line, within the range. */
654 ASSERT_TRUE (example_b
.contains_point (3, 15));
656 /* On an interior line.
657 The column number should not matter; try various boundary
659 ASSERT_TRUE (example_b
.contains_point (4, 1));
660 ASSERT_TRUE (example_b
.contains_point (4, 7));
661 ASSERT_TRUE (example_b
.contains_point (4, 8));
662 ASSERT_TRUE (example_b
.contains_point (4, 9));
663 ASSERT_TRUE (example_b
.contains_point (4, 13));
664 ASSERT_TRUE (example_b
.contains_point (4, 14));
665 ASSERT_TRUE (example_b
.contains_point (4, 15));
667 /* On the final line, before the end. */
668 ASSERT_TRUE (example_b
.contains_point (5, 7));
670 /* On the final line, at the end. */
671 ASSERT_TRUE (example_b
.contains_point (5, 8));
673 /* On the final line, after the end. */
674 ASSERT_FALSE (example_b
.contains_point (5, 9));
676 /* After the line. */
677 ASSERT_FALSE (example_b
.contains_point (6, 1));
679 /* Tests for layout_range::intersects_line_p. */
680 ASSERT_FALSE (example_b
.intersects_line_p (2));
681 ASSERT_TRUE (example_b
.intersects_line_p (3));
682 ASSERT_TRUE (example_b
.intersects_line_p (4));
683 ASSERT_TRUE (example_b
.intersects_line_p (5));
684 ASSERT_FALSE (example_b
.intersects_line_p (6));
687 #endif /* #if CHECKING_P */
689 /* Given a source line LINE of length LINE_WIDTH, determine the width
690 without any trailing whitespace. */
693 get_line_width_without_trailing_whitespace (const char *line
, int line_width
)
695 int result
= line_width
;
698 char ch
= line
[result
- 1];
699 if (ch
== ' ' || ch
== '\t' || ch
== '\r')
704 gcc_assert (result
>= 0);
705 gcc_assert (result
<= line_width
);
706 gcc_assert (result
== 0 ||
707 (line
[result
- 1] != ' '
708 && line
[result
-1] != '\t'
709 && line
[result
-1] != '\r'));
715 /* A helper function for testing get_line_width_without_trailing_whitespace. */
718 assert_eq (const char *line
, int expected_width
)
721 = get_line_width_without_trailing_whitespace (line
, strlen (line
));
722 ASSERT_EQ (actual_value
, expected_width
);
725 /* Verify that get_line_width_without_trailing_whitespace is sane for
726 various inputs. It is not required to handle newlines. */
729 test_get_line_width_without_trailing_whitespace ()
735 assert_eq ("hello world", 11);
736 assert_eq ("hello world ", 11);
737 assert_eq ("hello world \t\t ", 11);
738 assert_eq ("hello world\r", 11);
741 #endif /* #if CHECKING_P */
743 /* Helper function for layout's ctor, for sanitizing locations relative
744 to the primary location within a diagnostic.
746 Compare LOC_A and LOC_B to see if it makes sense to print underlines
747 connecting their expanded locations. Doing so is only guaranteed to
748 make sense if the locations share the same macro expansion "history"
749 i.e. they can be traced through the same macro expansions, eventually
750 reaching an ordinary map.
752 This may be too strong a condition, but it effectively sanitizes
753 PR c++/70105, which has an example of printing an expression where the
754 final location of the expression is in a different macro, which
755 erroneously was leading to hundreds of lines of irrelevant source
759 compatible_locations_p (location_t loc_a
, location_t loc_b
)
761 if (IS_ADHOC_LOC (loc_a
))
762 loc_a
= get_location_from_adhoc_loc (line_table
, loc_a
);
763 if (IS_ADHOC_LOC (loc_b
))
764 loc_b
= get_location_from_adhoc_loc (line_table
, loc_b
);
766 /* If either location is one of the special locations outside of a
767 linemap, they are only compatible if they are equal. */
768 if (loc_a
< RESERVED_LOCATION_COUNT
769 || loc_b
< RESERVED_LOCATION_COUNT
)
770 return loc_a
== loc_b
;
772 const line_map
*map_a
= linemap_lookup (line_table
, loc_a
);
773 linemap_assert (map_a
);
775 const line_map
*map_b
= linemap_lookup (line_table
, loc_b
);
776 linemap_assert (map_b
);
778 /* Are they within the same map? */
781 /* Are both within the same macro expansion? */
782 if (linemap_macro_expansion_map_p (map_a
))
784 /* Expand each location towards the spelling location, and
786 const line_map_macro
*macro_map
= linemap_check_macro (map_a
);
787 location_t loc_a_toward_spelling
788 = linemap_macro_map_loc_unwind_toward_spelling (line_table
,
791 location_t loc_b_toward_spelling
792 = linemap_macro_map_loc_unwind_toward_spelling (line_table
,
795 return compatible_locations_p (loc_a_toward_spelling
,
796 loc_b_toward_spelling
);
799 /* Otherwise they are within the same ordinary map. */
804 /* Within different maps. */
806 /* If either is within a macro expansion, they are incompatible. */
807 if (linemap_macro_expansion_map_p (map_a
)
808 || linemap_macro_expansion_map_p (map_b
))
811 /* Within two different ordinary maps; they are compatible iff they
812 are in the same file. */
813 const line_map_ordinary
*ord_map_a
= linemap_check_ordinary (map_a
);
814 const line_map_ordinary
*ord_map_b
= linemap_check_ordinary (map_b
);
815 return ord_map_a
->to_file
== ord_map_b
->to_file
;
819 /* Comparator for sorting fix-it hints. */
822 fixit_cmp (const void *p_a
, const void *p_b
)
824 const fixit_hint
* hint_a
= *static_cast<const fixit_hint
* const *> (p_a
);
825 const fixit_hint
* hint_b
= *static_cast<const fixit_hint
* const *> (p_b
);
826 return hint_a
->get_start_loc () - hint_b
->get_start_loc ();
829 /* Implementation of class layout. */
831 /* Constructor for class layout.
833 Filter the ranges from the rich_location to those that we can
834 sanely print, populating m_layout_ranges and m_fixit_hints.
835 Determine the range of lines that we will print, splitting them
836 up into an ordered list of disjoint spans of contiguous line numbers.
837 Determine m_x_offset, to ensure that the primary caret
838 will fit within the max_width provided by the diagnostic_context. */
840 layout::layout (diagnostic_context
* context
,
841 rich_location
*richloc
,
842 diagnostic_t diagnostic_kind
)
843 : m_context (context
),
844 m_pp (context
->printer
),
845 m_primary_loc (richloc
->get_range (0)->m_loc
),
846 m_exploc (richloc
->get_expanded_location (0)),
847 m_colorizer (context
, diagnostic_kind
),
848 m_colorize_source_p (context
->colorize_source_p
),
849 m_show_labels_p (context
->show_labels_p
),
850 m_show_line_numbers_p (context
->show_line_numbers_p
),
851 m_layout_ranges (richloc
->get_num_locations ()),
852 m_fixit_hints (richloc
->get_num_fixit_hints ()),
853 m_line_spans (1 + richloc
->get_num_locations ()),
857 for (unsigned int idx
= 0; idx
< richloc
->get_num_locations (); idx
++)
859 /* This diagnostic printer can only cope with "sufficiently sane" ranges.
860 Ignore any ranges that are awkward to handle. */
861 const location_range
*loc_range
= richloc
->get_range (idx
);
862 maybe_add_location_range (loc_range
, idx
, false);
865 /* Populate m_fixit_hints, filtering to only those that are in the
867 for (unsigned int i
= 0; i
< richloc
->get_num_fixit_hints (); i
++)
869 const fixit_hint
*hint
= richloc
->get_fixit_hint (i
);
870 if (validate_fixit_hint_p (hint
))
871 m_fixit_hints
.safe_push (hint
);
874 /* Sort m_fixit_hints. */
875 m_fixit_hints
.qsort (fixit_cmp
);
877 /* Populate m_line_spans. */
878 calculate_line_spans ();
880 /* Determine m_linenum_width. */
881 gcc_assert (m_line_spans
.length () > 0);
882 const line_span
*last_span
= &m_line_spans
[m_line_spans
.length () - 1];
883 int highest_line
= last_span
->m_last_line
;
884 if (highest_line
< 0)
886 m_linenum_width
= num_digits (highest_line
);
887 /* If we're showing jumps in the line-numbering, allow at least 3 chars. */
888 if (m_line_spans
.length () > 1)
889 m_linenum_width
= MAX (m_linenum_width
, 3);
890 /* If there's a minimum margin width, apply it (subtracting 1 for the space
891 after the line number. */
892 m_linenum_width
= MAX (m_linenum_width
, context
->min_margin_width
- 1);
894 /* Adjust m_x_offset.
895 Center the primary caret to fit in max_width; all columns
896 will be adjusted accordingly. */
897 size_t max_width
= m_context
->caret_max_width
;
898 char_span line
= location_get_source_line (m_exploc
.file
, m_exploc
.line
);
899 if (line
&& (size_t)m_exploc
.column
<= line
.length ())
901 size_t right_margin
= CARET_LINE_MARGIN
;
902 size_t column
= m_exploc
.column
;
903 if (m_show_line_numbers_p
)
904 column
+= m_linenum_width
+ 2;
905 right_margin
= MIN (line
.length () - column
, right_margin
);
906 right_margin
= max_width
- right_margin
;
907 if (line
.length () >= max_width
&& column
> right_margin
)
908 m_x_offset
= column
- right_margin
;
909 gcc_assert (m_x_offset
>= 0);
912 if (context
->show_ruler_p
)
913 show_ruler (m_x_offset
+ max_width
);
916 /* Attempt to add LOC_RANGE to m_layout_ranges, filtering them to
917 those that we can sanely print.
919 ORIGINAL_IDX is the index of LOC_RANGE within its rich_location,
920 (for use as extrinsic state by label ranges FIXME).
922 If RESTRICT_TO_CURRENT_LINE_SPANS is true, then LOC_RANGE is also
923 filtered against this layout instance's current line spans: it
924 will only be added if the location is fully within the lines
925 already specified by other locations.
927 Return true iff LOC_RANGE was added. */
930 layout::maybe_add_location_range (const location_range
*loc_range
,
931 unsigned original_idx
,
932 bool restrict_to_current_line_spans
)
934 gcc_assert (loc_range
);
936 /* Split the "range" into caret and range information. */
937 source_range src_range
= get_range_from_loc (line_table
, loc_range
->m_loc
);
939 /* Expand the various locations. */
940 expanded_location start
941 = linemap_client_expand_location_to_spelling_point
942 (src_range
.m_start
, LOCATION_ASPECT_START
);
943 expanded_location finish
944 = linemap_client_expand_location_to_spelling_point
945 (src_range
.m_finish
, LOCATION_ASPECT_FINISH
);
946 expanded_location caret
947 = linemap_client_expand_location_to_spelling_point
948 (loc_range
->m_loc
, LOCATION_ASPECT_CARET
);
950 /* If any part of the range isn't in the same file as the primary
951 location of this diagnostic, ignore the range. */
952 if (start
.file
!= m_exploc
.file
)
954 if (finish
.file
!= m_exploc
.file
)
956 if (loc_range
->m_range_display_kind
== SHOW_RANGE_WITH_CARET
)
957 if (caret
.file
!= m_exploc
.file
)
960 /* Sanitize the caret location for non-primary ranges. */
961 if (m_layout_ranges
.length () > 0)
962 if (loc_range
->m_range_display_kind
== SHOW_RANGE_WITH_CARET
)
963 if (!compatible_locations_p (loc_range
->m_loc
, m_primary_loc
))
964 /* Discard any non-primary ranges that can't be printed
965 sanely relative to the primary location. */
968 /* Everything is now known to be in the correct source file,
969 but it may require further sanitization. */
970 layout_range
ri (&start
, &finish
, loc_range
->m_range_display_kind
, &caret
,
971 original_idx
, loc_range
->m_label
);
973 /* If we have a range that finishes before it starts (perhaps
974 from something built via macro expansion), printing the
975 range is likely to be nonsensical. Also, attempting to do so
976 breaks assumptions within the printing code (PR c/68473).
977 Similarly, don't attempt to print ranges if one or both ends
978 of the range aren't sane to print relative to the
979 primary location (PR c++/70105). */
980 if (start
.line
> finish
.line
981 || !compatible_locations_p (src_range
.m_start
, m_primary_loc
)
982 || !compatible_locations_p (src_range
.m_finish
, m_primary_loc
))
984 /* Is this the primary location? */
985 if (m_layout_ranges
.length () == 0)
987 /* We want to print the caret for the primary location, but
988 we must sanitize away m_start and m_finish. */
989 ri
.m_start
= ri
.m_caret
;
990 ri
.m_finish
= ri
.m_caret
;
993 /* This is a non-primary range; ignore it. */
997 /* Potentially filter to just the lines already specified by other
998 locations. This is for use by gcc_rich_location::add_location_if_nearby.
999 The layout ctor doesn't use it, and can't because m_line_spans
1000 hasn't been set up at that point. */
1001 if (restrict_to_current_line_spans
)
1003 if (!will_show_line_p (start
.line
))
1005 if (!will_show_line_p (finish
.line
))
1007 if (loc_range
->m_range_display_kind
== SHOW_RANGE_WITH_CARET
)
1008 if (!will_show_line_p (caret
.line
))
1012 /* Passed all the tests; add the range to m_layout_ranges so that
1013 it will be printed. */
1014 m_layout_ranges
.safe_push (ri
);
1018 /* Return true iff ROW is within one of the line spans for this layout. */
1021 layout::will_show_line_p (linenum_type row
) const
1023 for (int line_span_idx
= 0; line_span_idx
< get_num_line_spans ();
1026 const line_span
*line_span
= get_line_span (line_span_idx
);
1027 if (line_span
->contains_line_p (row
))
1033 /* Print a line showing a gap in the line numbers, for showing the boundary
1034 between two line spans. */
1037 layout::print_gap_in_line_numbering ()
1039 gcc_assert (m_show_line_numbers_p
);
1041 for (int i
= 0; i
< m_linenum_width
+ 1; i
++)
1042 pp_character (m_pp
, '.');
1047 /* Return true iff we should print a heading when starting the
1048 line span with the given index. */
1051 layout::print_heading_for_line_span_index_p (int line_span_idx
) const
1053 /* We print a heading for every change of line span, hence for every
1054 line span after the initial one. */
1055 if (line_span_idx
> 0)
1058 /* We also do it for the initial span if the primary location of the
1059 diagnostic is in a different span. */
1060 if (m_exploc
.line
> (int)get_line_span (0)->m_last_line
)
1066 /* Get an expanded_location for the first location of interest within
1067 the given line_span.
1068 Used when printing a heading to indicate a new line span. */
1071 layout::get_expanded_location (const line_span
*line_span
) const
1073 /* Whenever possible, use the caret location. */
1074 if (line_span
->contains_line_p (m_exploc
.line
))
1077 /* Otherwise, use the start of the first range that's present
1078 within the line_span. */
1079 for (unsigned int i
= 0; i
< m_layout_ranges
.length (); i
++)
1081 const layout_range
*lr
= &m_layout_ranges
[i
];
1082 if (line_span
->contains_line_p (lr
->m_start
.m_line
))
1084 expanded_location exploc
= m_exploc
;
1085 exploc
.line
= lr
->m_start
.m_line
;
1086 exploc
.column
= lr
->m_start
.m_column
;
1091 /* Otherwise, use the location of the first fixit-hint present within
1093 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1095 const fixit_hint
*hint
= m_fixit_hints
[i
];
1096 location_t loc
= hint
->get_start_loc ();
1097 expanded_location exploc
= expand_location (loc
);
1098 if (line_span
->contains_line_p (exploc
.line
))
1102 /* It should not be possible to have a line span that didn't
1103 contain any of the layout_range or fixit_hint instances. */
1108 /* Determine if HINT is meaningful to print within this layout. */
1111 layout::validate_fixit_hint_p (const fixit_hint
*hint
)
1113 if (LOCATION_FILE (hint
->get_start_loc ()) != m_exploc
.file
)
1115 if (LOCATION_FILE (hint
->get_next_loc ()) != m_exploc
.file
)
1121 /* Determine the range of lines affected by HINT.
1122 This assumes that HINT has already been filtered by
1123 validate_fixit_hint_p, and so affects the correct source file. */
1126 get_line_span_for_fixit_hint (const fixit_hint
*hint
)
1130 int start_line
= LOCATION_LINE (hint
->get_start_loc ());
1132 /* For line-insertion fix-it hints, add the previous line to the
1133 span, to give the user more context on the proposed change. */
1134 if (hint
->ends_with_newline_p ())
1138 return line_span (start_line
,
1139 LOCATION_LINE (hint
->get_next_loc ()));
1142 /* We want to print the pertinent source code at a diagnostic. The
1143 rich_location can contain multiple locations. This will have been
1144 filtered into m_exploc (the caret for the primary location) and
1145 m_layout_ranges, for those ranges within the same source file.
1147 We will print a subset of the lines within the source file in question,
1148 as a collection of "spans" of lines.
1150 This function populates m_line_spans with an ordered, disjoint list of
1151 the line spans of interest.
1153 Printing a gap between line spans takes one line, so, when printing
1154 line numbers, we allow a gap of up to one line between spans when
1155 merging, since it makes more sense to print the source line rather than a
1156 "gap-in-line-numbering" line. When not printing line numbers, it's
1157 better to be more explicit about what's going on, so keeping them as
1158 separate spans is preferred.
1160 For example, if the primary range is on lines 8-10, with secondary ranges
1161 covering lines 5-6 and lines 13-15:
1177 With line numbering on, we want two spans: lines 5-10 and lines 13-15.
1179 With line numbering off (with span headers), we want three spans: lines 5-6,
1180 lines 8-10, and lines 13-15. */
1183 layout::calculate_line_spans ()
1185 /* This should only be called once, by the ctor. */
1186 gcc_assert (m_line_spans
.length () == 0);
1188 /* Populate tmp_spans with individual spans, for each of
1189 m_exploc, and for m_layout_ranges. */
1190 auto_vec
<line_span
> tmp_spans (1 + m_layout_ranges
.length ());
1191 tmp_spans
.safe_push (line_span (m_exploc
.line
, m_exploc
.line
));
1192 for (unsigned int i
= 0; i
< m_layout_ranges
.length (); i
++)
1194 const layout_range
*lr
= &m_layout_ranges
[i
];
1195 gcc_assert (lr
->m_start
.m_line
<= lr
->m_finish
.m_line
);
1196 tmp_spans
.safe_push (line_span (lr
->m_start
.m_line
,
1197 lr
->m_finish
.m_line
));
1200 /* Also add spans for any fix-it hints, in case they cover other lines. */
1201 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1203 const fixit_hint
*hint
= m_fixit_hints
[i
];
1205 tmp_spans
.safe_push (get_line_span_for_fixit_hint (hint
));
1209 tmp_spans
.qsort(line_span::comparator
);
1211 /* Now iterate through tmp_spans, copying into m_line_spans, and
1212 combining where possible. */
1213 gcc_assert (tmp_spans
.length () > 0);
1214 m_line_spans
.safe_push (tmp_spans
[0]);
1215 for (unsigned int i
= 1; i
< tmp_spans
.length (); i
++)
1217 line_span
*current
= &m_line_spans
[m_line_spans
.length () - 1];
1218 const line_span
*next
= &tmp_spans
[i
];
1219 gcc_assert (next
->m_first_line
>= current
->m_first_line
);
1220 const int merger_distance
= m_show_line_numbers_p
? 1 : 0;
1221 if ((linenum_arith_t
)next
->m_first_line
1222 <= (linenum_arith_t
)current
->m_last_line
+ 1 + merger_distance
)
1224 /* We can merge them. */
1225 if (next
->m_last_line
> current
->m_last_line
)
1226 current
->m_last_line
= next
->m_last_line
;
1230 /* No merger possible. */
1231 m_line_spans
.safe_push (*next
);
1235 /* Verify the result, in m_line_spans. */
1236 gcc_assert (m_line_spans
.length () > 0);
1237 for (unsigned int i
= 1; i
< m_line_spans
.length (); i
++)
1239 const line_span
*prev
= &m_line_spans
[i
- 1];
1240 const line_span
*next
= &m_line_spans
[i
];
1241 /* The individual spans must be sane. */
1242 gcc_assert (prev
->m_first_line
<= prev
->m_last_line
);
1243 gcc_assert (next
->m_first_line
<= next
->m_last_line
);
1244 /* The spans must be ordered. */
1245 gcc_assert (prev
->m_first_line
< next
->m_first_line
);
1246 /* There must be a gap of at least one line between separate spans. */
1247 gcc_assert ((prev
->m_last_line
+ 1) < next
->m_first_line
);
1251 /* Print line ROW of source code, potentially colorized at any ranges, and
1252 populate *LBOUNDS_OUT.
1253 LINE is the source line (not necessarily 0-terminated) and LINE_WIDTH
1257 layout::print_source_line (linenum_type row
, const char *line
, int line_width
,
1258 line_bounds
*lbounds_out
)
1260 m_colorizer
.set_normal_text ();
1262 /* We will stop printing the source line at any trailing
1264 line_width
= get_line_width_without_trailing_whitespace (line
,
1268 if (m_show_line_numbers_p
)
1270 int width
= num_digits (row
);
1271 for (int i
= 0; i
< m_linenum_width
- width
; i
++)
1273 pp_printf (m_pp
, "%i | ", row
);
1277 int first_non_ws
= INT_MAX
;
1278 int last_non_ws
= 0;
1280 for (column
= 1 + m_x_offset
; column
<= line_width
; column
++)
1282 /* Assuming colorization is enabled for the caret and underline
1283 characters, we may also colorize the associated characters
1284 within the source line.
1286 For frontends that generate range information, we color the
1287 associated characters in the source line the same as the
1288 carets and underlines in the annotation line, to make it easier
1289 for the reader to see the pertinent code.
1291 For frontends that only generate carets, we don't colorize the
1292 characters above them, since this would look strange (e.g.
1293 colorizing just the first character in a token). */
1294 if (m_colorize_source_p
)
1298 in_range_p
= get_state_at_point (row
, column
,
1302 m_colorizer
.set_range (state
.range_idx
);
1304 m_colorizer
.set_normal_text ();
1307 if (c
== '\0' || c
== '\t' || c
== '\r')
1311 last_non_ws
= column
;
1312 if (first_non_ws
== INT_MAX
)
1313 first_non_ws
= column
;
1315 pp_character (m_pp
, c
);
1320 lbounds_out
->m_first_non_ws
= first_non_ws
;
1321 lbounds_out
->m_last_non_ws
= last_non_ws
;
1324 /* Determine if we should print an annotation line for ROW.
1325 i.e. if any of m_layout_ranges contains ROW. */
1328 layout::should_print_annotation_line_p (linenum_type row
) const
1330 layout_range
*range
;
1332 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1334 if (range
->m_range_display_kind
== SHOW_LINES_WITHOUT_RANGE
)
1336 if (range
->intersects_line_p (row
))
1342 /* Begin an annotation line. If m_show_line_numbers_p, print the left
1343 margin, which is empty for annotation lines. Otherwise, do nothing. */
1346 layout::start_annotation_line (char margin_char
) const
1348 if (m_show_line_numbers_p
)
1350 /* Print the margin. If MARGIN_CHAR != ' ', then print up to 3
1351 of it, right-aligned, padded with spaces. */
1353 for (i
= 0; i
< m_linenum_width
- 3; i
++)
1355 for (; i
< m_linenum_width
; i
++)
1356 pp_character (m_pp
, margin_char
);
1357 pp_string (m_pp
, " |");
1361 /* Print a line consisting of the caret/underlines for the given
1365 layout::print_annotation_line (linenum_type row
, const line_bounds lbounds
)
1367 int x_bound
= get_x_bound_for_row (row
, m_exploc
.column
,
1368 lbounds
.m_last_non_ws
);
1370 start_annotation_line ();
1373 for (int column
= 1 + m_x_offset
; column
< x_bound
; column
++)
1377 in_range_p
= get_state_at_point (row
, column
,
1378 lbounds
.m_first_non_ws
,
1379 lbounds
.m_last_non_ws
,
1383 /* Within a range. Draw either the caret or an underline. */
1384 m_colorizer
.set_range (state
.range_idx
);
1385 if (state
.draw_caret_p
)
1387 /* Draw the caret. */
1389 if (state
.range_idx
< rich_location::STATICALLY_ALLOCATED_RANGES
)
1390 caret_char
= m_context
->caret_chars
[state
.range_idx
];
1393 pp_character (m_pp
, caret_char
);
1396 pp_character (m_pp
, '~');
1400 /* Not in a range. */
1401 m_colorizer
.set_normal_text ();
1402 pp_character (m_pp
, ' ');
1408 /* Implementation detail of layout::print_any_labels.
1410 A label within the given row of source. */
1414 line_label (int state_idx
, int column
, label_text text
)
1415 : m_state_idx (state_idx
), m_column (column
),
1416 m_text (text
), m_length (strlen (text
.m_buffer
)),
1420 /* Sorting is primarily by column, then by state index. */
1421 static int comparator (const void *p1
, const void *p2
)
1423 const line_label
*ll1
= (const line_label
*)p1
;
1424 const line_label
*ll2
= (const line_label
*)p2
;
1425 int column_cmp
= compare (ll1
->m_column
, ll2
->m_column
);
1428 return compare (ll1
->m_state_idx
, ll2
->m_state_idx
);
1438 /* Print any labels in this row. */
1440 layout::print_any_labels (linenum_type row
)
1443 auto_vec
<line_label
> labels
;
1445 /* Gather the labels that are to be printed into "labels". */
1447 layout_range
*range
;
1448 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1450 /* Most ranges don't have labels, so reject this first. */
1451 if (range
->m_label
== NULL
)
1454 /* The range's caret must be on this line. */
1455 if (range
->m_caret
.m_line
!= row
)
1458 /* Reject labels that aren't fully visible due to clipping
1460 if (range
->m_caret
.m_column
<= m_x_offset
)
1464 text
= range
->m_label
->get_text (range
->m_original_idx
);
1466 /* Allow for labels that return NULL from their get_text
1467 implementation (so e.g. such labels can control their own
1469 if (text
.m_buffer
== NULL
)
1472 labels
.safe_push (line_label (i
, range
->m_caret
.m_column
, text
));
1476 /* Bail out if there are no labels on this row. */
1477 if (labels
.length () == 0)
1481 labels
.qsort(line_label::comparator
);
1483 /* Figure out how many "label lines" we need, and which
1484 one each label is printed in.
1486 For example, if the labels aren't too densely packed,
1487 we can fit them on the same line, giving two "label lines":
1492 l0 l1 : label line 1
1494 If they would touch each other or overlap, then we need
1495 additional "label lines":
1500 | label 1 : label line 1
1501 label 0 : label line 2
1503 Place the final label on label line 1, and work backwards, adding
1504 label lines as needed.
1506 If multiple labels are at the same place, put them on separate
1512 label 1 : label line 2
1513 label 0 : label line 3. */
1515 int max_label_line
= 1;
1517 int next_column
= INT_MAX
;
1519 FOR_EACH_VEC_ELT_REVERSE (labels
, i
, label
)
1521 /* Would this label "touch" or overlap the next label? */
1522 if (label
->m_column
+ label
->m_length
>= (size_t)next_column
)
1525 label
->m_label_line
= max_label_line
;
1526 next_column
= label
->m_column
;
1530 /* Print the "label lines". For each label within the line, print
1531 either a vertical bar ('|') for the labels that are lower down, or the
1532 labels themselves once we've reached their line. */
1534 /* Keep track of in which column we last printed a vertical bar.
1535 This allows us to suppress duplicate vertical bars for the case
1536 where multiple labels are on one column. */
1538 for (int label_line
= 0; label_line
<= max_label_line
; label_line
++)
1540 start_annotation_line ();
1542 int column
= 1 + m_x_offset
;
1544 FOR_EACH_VEC_ELT (labels
, i
, label
)
1546 if (label_line
> label
->m_label_line
)
1547 /* We've printed all the labels for this label line. */
1550 if (label_line
== label
->m_label_line
)
1552 gcc_assert (column
<= label
->m_column
);
1553 move_to_column (&column
, label
->m_column
, true);
1554 m_colorizer
.set_range (label
->m_state_idx
);
1555 pp_string (m_pp
, label
->m_text
.m_buffer
);
1556 m_colorizer
.set_normal_text ();
1557 column
+= label
->m_length
;
1559 else if (label
->m_column
!= last_vbar
)
1561 gcc_assert (column
<= label
->m_column
);
1562 move_to_column (&column
, label
->m_column
, true);
1563 m_colorizer
.set_range (label
->m_state_idx
);
1564 pp_character (m_pp
, '|');
1565 m_colorizer
.set_normal_text ();
1577 FOR_EACH_VEC_ELT (labels
, i
, label
)
1578 label
->m_text
.maybe_free ();
1582 /* If there are any fixit hints inserting new lines before source line ROW,
1585 They are printed on lines of their own, before the source line
1586 itself, with a leading '+'. */
1589 layout::print_leading_fixits (linenum_type row
)
1591 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1593 const fixit_hint
*hint
= m_fixit_hints
[i
];
1595 if (!hint
->ends_with_newline_p ())
1596 /* Not a newline fixit; print it in print_trailing_fixits. */
1599 gcc_assert (hint
->insertion_p ());
1601 if (hint
->affects_line_p (m_exploc
.file
, row
))
1603 /* Printing the '+' with normal colorization
1604 and the inserted line with "insert" colorization
1605 helps them stand out from each other, and from
1606 the surrounding text. */
1607 m_colorizer
.set_normal_text ();
1608 start_annotation_line ('+');
1609 pp_character (m_pp
, '+');
1610 m_colorizer
.set_fixit_insert ();
1611 /* Print all but the trailing newline of the fix-it hint.
1612 We have to print the newline separately to avoid
1613 getting additional pp prefixes printed. */
1614 for (size_t i
= 0; i
< hint
->get_length () - 1; i
++)
1615 pp_character (m_pp
, hint
->get_string ()[i
]);
1616 m_colorizer
.set_normal_text ();
1622 /* Subroutine of layout::print_trailing_fixits.
1624 Determine if the annotation line printed for LINE contained
1625 the exact range from START_COLUMN to FINISH_COLUMN. */
1628 layout::annotation_line_showed_range_p (linenum_type line
, int start_column
,
1629 int finish_column
) const
1631 layout_range
*range
;
1633 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1634 if (range
->m_start
.m_line
== line
1635 && range
->m_start
.m_column
== start_column
1636 && range
->m_finish
.m_line
== line
1637 && range
->m_finish
.m_column
== finish_column
)
1642 /* Classes for printing trailing fix-it hints i.e. those that
1643 don't add new lines.
1645 For insertion, these can look like:
1649 For replacement, these can look like:
1651 ------------- : underline showing affected range
1654 For deletion, these can look like:
1656 ------------- : underline showing affected range
1658 This can become confusing if they overlap, and so we need
1659 to do some preprocessing to decide what to print.
1660 We use the list of fixit_hint instances affecting the line
1661 to build a list of "correction" instances, and print the
1664 For example, consider a set of fix-its for converting
1665 a C-style cast to a C++ const_cast.
1669 ..000000000111111111122222222223333333333.
1670 ..123456789012345678901234567890123456789.
1671 foo *f = (foo *)ptr->field;
1674 and the fix-it hints:
1675 - replace col 10 (the open paren) with "const_cast<"
1676 - replace col 16 (the close paren) with "> ("
1677 - insert ")" before col 27
1679 then we would get odd-looking output:
1681 foo *f = (foo *)ptr->field;
1688 It would be better to detect when fixit hints are going to
1689 overlap (those that require new lines), and to consolidate
1690 the printing of such fixits, giving something like:
1692 foo *f = (foo *)ptr->field;
1695 const_cast<foo *> (ptr->field)
1697 This works by detecting when the printing would overlap, and
1698 effectively injecting no-op replace hints into the gaps between
1699 such fix-its, so that the printing joins up.
1701 In the above example, the overlap of:
1702 - replace col 10 (the open paren) with "const_cast<"
1704 - replace col 16 (the close paren) with "> ("
1705 is fixed by injecting a no-op:
1706 - replace cols 11-15 with themselves ("foo *")
1707 and consolidating these, making:
1708 - replace cols 10-16 with "const_cast<" + "foo *" + "> ("
1710 - replace cols 10-16 with "const_cast<foo *> ("
1712 This overlaps with the final fix-it hint:
1713 - insert ")" before col 27
1714 and so we repeat the consolidation process, by injecting
1716 - replace cols 17-26 with themselves ("ptr->field")
1718 - replace cols 10-26 with "const_cast<foo *> (" + "ptr->field" + ")"
1720 - replace cols 10-26 with "const_cast<foo *> (ptr->field)"
1722 and is thus printed as desired. */
1724 /* A range of columns within a line. */
1728 column_range (int start_
, int finish_
) : start (start_
), finish (finish_
)
1730 /* We must have either a range, or an insertion. */
1731 gcc_assert (start
<= finish
|| finish
== start
- 1);
1734 bool operator== (const column_range
&other
) const
1736 return start
== other
.start
&& finish
== other
.finish
;
1743 /* Get the range of columns that HINT would affect. */
1746 get_affected_columns (const fixit_hint
*hint
)
1748 int start_column
= LOCATION_COLUMN (hint
->get_start_loc ());
1749 int finish_column
= LOCATION_COLUMN (hint
->get_next_loc ()) - 1;
1751 return column_range (start_column
, finish_column
);
1754 /* Get the range of columns that would be printed for HINT. */
1757 get_printed_columns (const fixit_hint
*hint
)
1759 int start_column
= LOCATION_COLUMN (hint
->get_start_loc ());
1760 int final_hint_column
= start_column
+ hint
->get_length () - 1;
1761 if (hint
->insertion_p ())
1763 return column_range (start_column
, final_hint_column
);
1767 int finish_column
= LOCATION_COLUMN (hint
->get_next_loc ()) - 1;
1769 return column_range (start_column
,
1770 MAX (finish_column
, final_hint_column
));
1774 /* A correction on a particular line.
1775 This describes a plan for how to print one or more fixit_hint
1776 instances that affected the line, potentially consolidating hints
1777 into corrections to make the result easier for the user to read. */
1781 correction (column_range affected_columns
,
1782 column_range printed_columns
,
1783 const char *new_text
, size_t new_text_len
)
1784 : m_affected_columns (affected_columns
),
1785 m_printed_columns (printed_columns
),
1786 m_text (xstrdup (new_text
)),
1787 m_len (new_text_len
),
1788 m_alloc_sz (new_text_len
+ 1)
1792 ~correction () { free (m_text
); }
1794 bool insertion_p () const
1796 return m_affected_columns
.start
== m_affected_columns
.finish
+ 1;
1799 void ensure_capacity (size_t len
);
1800 void ensure_terminated ();
1802 void overwrite (int dst_offset
, const char_span
&src_span
)
1804 gcc_assert (dst_offset
>= 0);
1805 gcc_assert (dst_offset
+ src_span
.length () < m_alloc_sz
);
1806 memcpy (m_text
+ dst_offset
, src_span
.get_buffer (),
1807 src_span
.length ());
1810 /* If insert, then start: the column before which the text
1811 is to be inserted, and finish is offset by the length of
1813 If replace, then the range of columns affected. */
1814 column_range m_affected_columns
;
1816 /* If insert, then start: the column before which the text
1817 is to be inserted, and finish is offset by the length of
1819 If replace, then the range of columns affected. */
1820 column_range m_printed_columns
;
1822 /* The text to be inserted/used as replacement. */
1828 /* Ensure that m_text can hold a string of length LEN
1829 (plus 1 for 0-termination). */
1832 correction::ensure_capacity (size_t len
)
1834 /* Allow 1 extra byte for 0-termination. */
1835 if (m_alloc_sz
< (len
+ 1))
1837 size_t new_alloc_sz
= (len
+ 1) * 2;
1838 m_text
= (char *)xrealloc (m_text
, new_alloc_sz
);
1839 m_alloc_sz
= new_alloc_sz
;
1843 /* Ensure that m_text is 0-terminated. */
1846 correction::ensure_terminated ()
1848 /* 0-terminate the buffer. */
1849 gcc_assert (m_len
< m_alloc_sz
);
1850 m_text
[m_len
] = '\0';
1853 /* A list of corrections affecting a particular line.
1854 This is used by layout::print_trailing_fixits for planning
1855 how to print the fix-it hints affecting the line. */
1857 struct line_corrections
1859 line_corrections (const char *filename
, linenum_type row
)
1860 : m_filename (filename
), m_row (row
)
1862 ~line_corrections ();
1864 void add_hint (const fixit_hint
*hint
);
1866 const char *m_filename
;
1868 auto_vec
<correction
*> m_corrections
;
1871 /* struct line_corrections. */
1873 line_corrections::~line_corrections ()
1877 FOR_EACH_VEC_ELT (m_corrections
, i
, c
)
1881 /* A struct wrapping a particular source line, allowing
1882 run-time bounds-checking of accesses in a checked build. */
1886 source_line (const char *filename
, int line
);
1888 char_span
as_span () { return char_span (chars
, width
); }
1894 /* source_line's ctor. */
1896 source_line::source_line (const char *filename
, int line
)
1898 char_span span
= location_get_source_line (filename
, line
);
1899 chars
= span
.get_buffer ();
1900 width
= span
.length ();
1903 /* Add HINT to the corrections for this line.
1904 Attempt to consolidate nearby hints so that they will not
1905 overlap with printed. */
1908 line_corrections::add_hint (const fixit_hint
*hint
)
1910 column_range affected_columns
= get_affected_columns (hint
);
1911 column_range printed_columns
= get_printed_columns (hint
);
1913 /* Potentially consolidate. */
1914 if (!m_corrections
.is_empty ())
1916 correction
*last_correction
1917 = m_corrections
[m_corrections
.length () - 1];
1919 /* The following consolidation code assumes that the fix-it hints
1920 have been sorted by start (done within layout's ctor). */
1921 gcc_assert (affected_columns
.start
1922 >= last_correction
->m_affected_columns
.start
);
1923 gcc_assert (printed_columns
.start
1924 >= last_correction
->m_printed_columns
.start
);
1926 if (printed_columns
.start
<= last_correction
->m_printed_columns
.finish
)
1928 /* We have two hints for which the printed forms of the hints
1929 would touch or overlap, so we need to consolidate them to avoid
1931 Attempt to inject a "replace" correction from immediately
1932 after the end of the last hint to immediately before the start
1933 of the next hint. */
1934 column_range
between (last_correction
->m_affected_columns
.finish
+ 1,
1935 printed_columns
.start
- 1);
1937 /* Try to read the source. */
1938 source_line
line (m_filename
, m_row
);
1939 if (line
.chars
&& between
.finish
< line
.width
)
1941 /* Consolidate into the last correction:
1942 add a no-op "replace" of the "between" text, and
1943 add the text from the new hint. */
1944 int old_len
= last_correction
->m_len
;
1945 gcc_assert (old_len
>= 0);
1946 int between_len
= between
.finish
+ 1 - between
.start
;
1947 gcc_assert (between_len
>= 0);
1948 int new_len
= old_len
+ between_len
+ hint
->get_length ();
1949 gcc_assert (new_len
>= 0);
1950 last_correction
->ensure_capacity (new_len
);
1951 last_correction
->overwrite
1953 line
.as_span ().subspan (between
.start
- 1,
1954 between
.finish
+ 1 - between
.start
));
1955 last_correction
->overwrite (old_len
+ between_len
,
1956 char_span (hint
->get_string (),
1957 hint
->get_length ()));
1958 last_correction
->m_len
= new_len
;
1959 last_correction
->ensure_terminated ();
1960 last_correction
->m_affected_columns
.finish
1961 = affected_columns
.finish
;
1962 last_correction
->m_printed_columns
.finish
1963 += between_len
+ hint
->get_length ();
1969 /* If no consolidation happened, add a new correction instance. */
1970 m_corrections
.safe_push (new correction (affected_columns
,
1972 hint
->get_string (),
1973 hint
->get_length ()));
1976 /* If there are any fixit hints on source line ROW, print them.
1977 They are printed in order, attempting to combine them onto lines, but
1978 starting new lines if necessary.
1979 Fix-it hints that insert new lines are handled separately,
1980 in layout::print_leading_fixits. */
1983 layout::print_trailing_fixits (linenum_type row
)
1985 /* Build a list of correction instances for the line,
1986 potentially consolidating hints (for the sake of readability). */
1987 line_corrections
corrections (m_exploc
.file
, row
);
1988 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1990 const fixit_hint
*hint
= m_fixit_hints
[i
];
1992 /* Newline fixits are handled by layout::print_leading_fixits. */
1993 if (hint
->ends_with_newline_p ())
1996 if (hint
->affects_line_p (m_exploc
.file
, row
))
1997 corrections
.add_hint (hint
);
2000 /* Now print the corrections. */
2003 int column
= m_x_offset
;
2005 if (!corrections
.m_corrections
.is_empty ())
2006 start_annotation_line ();
2008 FOR_EACH_VEC_ELT (corrections
.m_corrections
, i
, c
)
2010 /* For now we assume each fixit hint can only touch one line. */
2011 if (c
->insertion_p ())
2013 /* This assumes the insertion just affects one line. */
2014 int start_column
= c
->m_printed_columns
.start
;
2015 move_to_column (&column
, start_column
, true);
2016 m_colorizer
.set_fixit_insert ();
2017 pp_string (m_pp
, c
->m_text
);
2018 m_colorizer
.set_normal_text ();
2023 /* If the range of the replacement wasn't printed in the
2024 annotation line, then print an extra underline to
2025 indicate exactly what is being replaced.
2026 Always show it for removals. */
2027 int start_column
= c
->m_affected_columns
.start
;
2028 int finish_column
= c
->m_affected_columns
.finish
;
2029 if (!annotation_line_showed_range_p (row
, start_column
,
2033 move_to_column (&column
, start_column
, true);
2034 m_colorizer
.set_fixit_delete ();
2035 for (; column
<= finish_column
; column
++)
2036 pp_character (m_pp
, '-');
2037 m_colorizer
.set_normal_text ();
2039 /* Print the replacement text. REPLACE also covers
2040 removals, so only do this extra work (potentially starting
2041 a new line) if we have actual replacement text. */
2044 move_to_column (&column
, start_column
, true);
2045 m_colorizer
.set_fixit_insert ();
2046 pp_string (m_pp
, c
->m_text
);
2047 m_colorizer
.set_normal_text ();
2053 /* Add a trailing newline, if necessary. */
2054 move_to_column (&column
, 0, false);
2057 /* Disable any colorization and emit a newline. */
2060 layout::print_newline ()
2062 m_colorizer
.set_normal_text ();
2066 /* Return true if (ROW/COLUMN) is within a range of the layout.
2067 If it returns true, OUT_STATE is written to, with the
2068 range index, and whether we should draw the caret at
2069 (ROW/COLUMN) (as opposed to an underline). */
2072 layout::get_state_at_point (/* Inputs. */
2073 linenum_type row
, int column
,
2074 int first_non_ws
, int last_non_ws
,
2076 point_state
*out_state
)
2078 layout_range
*range
;
2080 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
2082 if (range
->m_range_display_kind
== SHOW_LINES_WITHOUT_RANGE
)
2083 /* Bail out early, so that such ranges don't affect underlining or
2084 source colorization. */
2087 if (range
->contains_point (row
, column
))
2089 out_state
->range_idx
= i
;
2091 /* Are we at the range's caret? is it visible? */
2092 out_state
->draw_caret_p
= false;
2093 if (range
->m_range_display_kind
== SHOW_RANGE_WITH_CARET
2094 && row
== range
->m_caret
.m_line
2095 && column
== range
->m_caret
.m_column
)
2096 out_state
->draw_caret_p
= true;
2098 /* Within a multiline range, don't display any underline
2099 in any leading or trailing whitespace on a line.
2100 We do display carets, however. */
2101 if (!out_state
->draw_caret_p
)
2102 if (column
< first_non_ws
|| column
> last_non_ws
)
2105 /* We are within a range. */
2113 /* Helper function for use by layout::print_line when printing the
2114 annotation line under the source line.
2115 Get the column beyond the rightmost one that could contain a caret or
2116 range marker, given that we stop rendering at trailing whitespace.
2117 ROW is the source line within the given file.
2118 CARET_COLUMN is the column of range 0's caret.
2119 LAST_NON_WS_COLUMN is the last column containing a non-whitespace
2120 character of source (as determined when printing the source line). */
2123 layout::get_x_bound_for_row (linenum_type row
, int caret_column
,
2124 int last_non_ws_column
)
2126 int result
= caret_column
+ 1;
2128 layout_range
*range
;
2130 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
2132 if (row
>= range
->m_start
.m_line
)
2134 if (range
->m_finish
.m_line
== row
)
2136 /* On the final line within a range; ensure that
2137 we render up to the end of the range. */
2138 if (result
<= range
->m_finish
.m_column
)
2139 result
= range
->m_finish
.m_column
+ 1;
2141 else if (row
< range
->m_finish
.m_line
)
2143 /* Within a multiline range; ensure that we render up to the
2144 last non-whitespace column. */
2145 if (result
<= last_non_ws_column
)
2146 result
= last_non_ws_column
+ 1;
2154 /* Given *COLUMN as an x-coordinate, print spaces to position
2155 successive output at DEST_COLUMN, printing a newline if necessary,
2156 and updating *COLUMN. If ADD_LEFT_MARGIN, then print the (empty)
2157 left margin after any newline. */
2160 layout::move_to_column (int *column
, int dest_column
, bool add_left_margin
)
2162 /* Start a new line if we need to. */
2163 if (*column
> dest_column
)
2166 if (add_left_margin
)
2167 start_annotation_line ();
2168 *column
= m_x_offset
;
2171 while (*column
< dest_column
)
2178 /* For debugging layout issues, render a ruler giving column numbers
2179 (after the 1-column indent). */
2182 layout::show_ruler (int max_column
) const
2185 if (max_column
> 99)
2187 start_annotation_line ();
2189 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
2190 if (column
% 10 == 0)
2191 pp_character (m_pp
, '0' + (column
/ 100) % 10);
2198 start_annotation_line ();
2200 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
2201 if (column
% 10 == 0)
2202 pp_character (m_pp
, '0' + (column
/ 10) % 10);
2208 start_annotation_line ();
2210 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
2211 pp_character (m_pp
, '0' + (column
% 10));
2215 /* Print leading fix-its (for new lines inserted before the source line)
2216 then the source line, followed by an annotation line
2217 consisting of any caret/underlines, then any fixits.
2218 If the source line can't be read, print nothing. */
2220 layout::print_line (linenum_type row
)
2222 char_span line
= location_get_source_line (m_exploc
.file
, row
);
2226 line_bounds lbounds
;
2227 print_leading_fixits (row
);
2228 print_source_line (row
, line
.get_buffer (), line
.length (), &lbounds
);
2229 if (should_print_annotation_line_p (row
))
2230 print_annotation_line (row
, lbounds
);
2231 if (m_show_labels_p
)
2232 print_any_labels (row
);
2233 print_trailing_fixits (row
);
2236 } /* End of anonymous namespace. */
2238 /* If LOC is within the spans of lines that will already be printed for
2239 this gcc_rich_location, then add it as a secondary location and return true.
2241 Otherwise return false. */
2244 gcc_rich_location::add_location_if_nearby (location_t loc
)
2246 /* Use the layout location-handling logic to sanitize LOC,
2247 filtering it to the current line spans within a temporary
2249 layout
layout (global_dc
, this, DK_ERROR
);
2250 location_range loc_range
;
2251 loc_range
.m_loc
= loc
;
2252 loc_range
.m_range_display_kind
= SHOW_RANGE_WITHOUT_CARET
;
2253 if (!layout
.maybe_add_location_range (&loc_range
, 0, true))
2260 /* Print the physical source code corresponding to the location of
2261 this diagnostic, with additional annotations. */
2264 diagnostic_show_locus (diagnostic_context
* context
,
2265 rich_location
*richloc
,
2266 diagnostic_t diagnostic_kind
)
2268 pp_newline (context
->printer
);
2270 location_t loc
= richloc
->get_loc ();
2271 /* Do nothing if source-printing has been disabled. */
2272 if (!context
->show_caret
)
2275 /* Don't attempt to print source for UNKNOWN_LOCATION and for builtins. */
2276 if (loc
<= BUILTINS_LOCATION
)
2279 /* Don't print the same source location twice in a row, unless we have
2281 if (loc
== context
->last_location
2282 && richloc
->get_num_fixit_hints () == 0)
2285 context
->last_location
= loc
;
2287 char *saved_prefix
= pp_take_prefix (context
->printer
);
2288 pp_set_prefix (context
->printer
, NULL
);
2290 layout
layout (context
, richloc
, diagnostic_kind
);
2291 for (int line_span_idx
= 0; line_span_idx
< layout
.get_num_line_spans ();
2294 const line_span
*line_span
= layout
.get_line_span (line_span_idx
);
2295 if (context
->show_line_numbers_p
)
2297 /* With line numbers, we should show whenever the line-numbering
2299 if (line_span_idx
> 0)
2300 layout
.print_gap_in_line_numbering ();
2304 /* Without line numbers, we print headings for some line spans. */
2305 if (layout
.print_heading_for_line_span_index_p (line_span_idx
))
2307 expanded_location exploc
2308 = layout
.get_expanded_location (line_span
);
2309 context
->start_span (context
, exploc
);
2312 /* Iterate over the lines within this span (using linenum_arith_t to
2313 avoid overflow with 0xffffffff causing an infinite loop). */
2314 linenum_arith_t last_line
= line_span
->get_last_line ();
2315 for (linenum_arith_t row
= line_span
->get_first_line ();
2316 row
<= last_line
; row
++)
2317 layout
.print_line (row
);
2320 pp_set_prefix (context
->printer
, saved_prefix
);
2325 namespace selftest
{
2327 /* Selftests for diagnostic_show_locus. */
2329 /* Verify that diagnostic_show_locus works sanely on UNKNOWN_LOCATION. */
2332 test_diagnostic_show_locus_unknown_location ()
2334 test_diagnostic_context dc
;
2335 rich_location
richloc (line_table
, UNKNOWN_LOCATION
);
2336 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2337 ASSERT_STREQ ("\n", pp_formatted_text (dc
.printer
));
2340 /* Verify that diagnostic_show_locus works sanely for various
2343 All of these work on the following 1-line source file:
2346 "foo = bar.field;\n"
2347 which is set up by test_diagnostic_show_locus_one_liner and calls
2353 test_one_liner_simple_caret ()
2355 test_diagnostic_context dc
;
2356 location_t caret
= linemap_position_for_column (line_table
, 10);
2357 rich_location
richloc (line_table
, caret
);
2358 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2360 " foo = bar.field;\n"
2362 pp_formatted_text (dc
.printer
));
2365 /* Caret and range. */
2368 test_one_liner_caret_and_range ()
2370 test_diagnostic_context dc
;
2371 location_t caret
= linemap_position_for_column (line_table
, 10);
2372 location_t start
= linemap_position_for_column (line_table
, 7);
2373 location_t finish
= linemap_position_for_column (line_table
, 15);
2374 location_t loc
= make_location (caret
, start
, finish
);
2375 rich_location
richloc (line_table
, loc
);
2376 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2378 " foo = bar.field;\n"
2380 pp_formatted_text (dc
.printer
));
2383 /* Multiple ranges and carets. */
2386 test_one_liner_multiple_carets_and_ranges ()
2388 test_diagnostic_context dc
;
2390 = make_location (linemap_position_for_column (line_table
, 2),
2391 linemap_position_for_column (line_table
, 1),
2392 linemap_position_for_column (line_table
, 3));
2393 dc
.caret_chars
[0] = 'A';
2396 = make_location (linemap_position_for_column (line_table
, 8),
2397 linemap_position_for_column (line_table
, 7),
2398 linemap_position_for_column (line_table
, 9));
2399 dc
.caret_chars
[1] = 'B';
2402 = make_location (linemap_position_for_column (line_table
, 13),
2403 linemap_position_for_column (line_table
, 11),
2404 linemap_position_for_column (line_table
, 15));
2405 dc
.caret_chars
[2] = 'C';
2407 rich_location
richloc (line_table
, foo
);
2408 richloc
.add_range (bar
, SHOW_RANGE_WITH_CARET
);
2409 richloc
.add_range (field
, SHOW_RANGE_WITH_CARET
);
2410 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2412 " foo = bar.field;\n"
2414 pp_formatted_text (dc
.printer
));
2417 /* Insertion fix-it hint: adding an "&" to the front of "bar.field". */
2420 test_one_liner_fixit_insert_before ()
2422 test_diagnostic_context dc
;
2423 location_t caret
= linemap_position_for_column (line_table
, 7);
2424 rich_location
richloc (line_table
, caret
);
2425 richloc
.add_fixit_insert_before ("&");
2426 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2428 " foo = bar.field;\n"
2431 pp_formatted_text (dc
.printer
));
2434 /* Insertion fix-it hint: adding a "[0]" after "foo". */
2437 test_one_liner_fixit_insert_after ()
2439 test_diagnostic_context dc
;
2440 location_t start
= linemap_position_for_column (line_table
, 1);
2441 location_t finish
= linemap_position_for_column (line_table
, 3);
2442 location_t foo
= make_location (start
, start
, finish
);
2443 rich_location
richloc (line_table
, foo
);
2444 richloc
.add_fixit_insert_after ("[0]");
2445 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2447 " foo = bar.field;\n"
2450 pp_formatted_text (dc
.printer
));
2453 /* Removal fix-it hint: removal of the ".field". */
2456 test_one_liner_fixit_remove ()
2458 test_diagnostic_context dc
;
2459 location_t start
= linemap_position_for_column (line_table
, 10);
2460 location_t finish
= linemap_position_for_column (line_table
, 15);
2461 location_t dot
= make_location (start
, start
, finish
);
2462 rich_location
richloc (line_table
, dot
);
2463 richloc
.add_fixit_remove ();
2464 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2466 " foo = bar.field;\n"
2469 pp_formatted_text (dc
.printer
));
2472 /* Replace fix-it hint: replacing "field" with "m_field". */
2475 test_one_liner_fixit_replace ()
2477 test_diagnostic_context dc
;
2478 location_t start
= linemap_position_for_column (line_table
, 11);
2479 location_t finish
= linemap_position_for_column (line_table
, 15);
2480 location_t field
= make_location (start
, start
, finish
);
2481 rich_location
richloc (line_table
, field
);
2482 richloc
.add_fixit_replace ("m_field");
2483 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2485 " foo = bar.field;\n"
2488 pp_formatted_text (dc
.printer
));
2491 /* Replace fix-it hint: replacing "field" with "m_field",
2492 but where the caret was elsewhere. */
2495 test_one_liner_fixit_replace_non_equal_range ()
2497 test_diagnostic_context dc
;
2498 location_t equals
= linemap_position_for_column (line_table
, 5);
2499 location_t start
= linemap_position_for_column (line_table
, 11);
2500 location_t finish
= linemap_position_for_column (line_table
, 15);
2501 rich_location
richloc (line_table
, equals
);
2503 range
.m_start
= start
;
2504 range
.m_finish
= finish
;
2505 richloc
.add_fixit_replace (range
, "m_field");
2506 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2507 /* The replacement range is not indicated in the annotation line, so
2508 it should be indicated via an additional underline. */
2510 " foo = bar.field;\n"
2514 pp_formatted_text (dc
.printer
));
2517 /* Replace fix-it hint: replacing "field" with "m_field",
2518 where the caret was elsewhere, but where a secondary range
2519 exactly covers "field". */
2522 test_one_liner_fixit_replace_equal_secondary_range ()
2524 test_diagnostic_context dc
;
2525 location_t equals
= linemap_position_for_column (line_table
, 5);
2526 location_t start
= linemap_position_for_column (line_table
, 11);
2527 location_t finish
= linemap_position_for_column (line_table
, 15);
2528 rich_location
richloc (line_table
, equals
);
2529 location_t field
= make_location (start
, start
, finish
);
2530 richloc
.add_range (field
);
2531 richloc
.add_fixit_replace (field
, "m_field");
2532 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2533 /* The replacement range is indicated in the annotation line,
2534 so it shouldn't be indicated via an additional underline. */
2536 " foo = bar.field;\n"
2539 pp_formatted_text (dc
.printer
));
2542 /* Verify that we can use ad-hoc locations when adding fixits to a
2546 test_one_liner_fixit_validation_adhoc_locations ()
2548 /* Generate a range that's too long to be packed, so must
2549 be stored as an ad-hoc location (given the defaults
2550 of 5 bits or 0 bits of packed range); 41 columns > 2**5. */
2551 const location_t c7
= linemap_position_for_column (line_table
, 7);
2552 const location_t c47
= linemap_position_for_column (line_table
, 47);
2553 const location_t loc
= make_location (c7
, c7
, c47
);
2555 if (c47
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2558 ASSERT_TRUE (IS_ADHOC_LOC (loc
));
2562 rich_location
richloc (line_table
, loc
);
2563 richloc
.add_fixit_insert_before (loc
, "test");
2564 /* It should not have been discarded by the validator. */
2565 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2567 test_diagnostic_context dc
;
2568 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2570 " foo = bar.field;\n"
2573 pp_formatted_text (dc
.printer
));
2578 rich_location
richloc (line_table
, loc
);
2579 source_range range
= source_range::from_locations (loc
, c47
);
2580 richloc
.add_fixit_remove (range
);
2581 /* It should not have been discarded by the validator. */
2582 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2584 test_diagnostic_context dc
;
2585 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2587 " foo = bar.field;\n"
2589 " -----------------------------------------\n",
2590 pp_formatted_text (dc
.printer
));
2595 rich_location
richloc (line_table
, loc
);
2596 source_range range
= source_range::from_locations (loc
, c47
);
2597 richloc
.add_fixit_replace (range
, "test");
2598 /* It should not have been discarded by the validator. */
2599 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2601 test_diagnostic_context dc
;
2602 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2604 " foo = bar.field;\n"
2607 pp_formatted_text (dc
.printer
));
2611 /* Test of consolidating insertions at the same location. */
2614 test_one_liner_many_fixits_1 ()
2616 test_diagnostic_context dc
;
2617 location_t equals
= linemap_position_for_column (line_table
, 5);
2618 rich_location
richloc (line_table
, equals
);
2619 for (int i
= 0; i
< 19; i
++)
2620 richloc
.add_fixit_insert_before ("a");
2621 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2622 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2624 " foo = bar.field;\n"
2626 " aaaaaaaaaaaaaaaaaaa\n",
2627 pp_formatted_text (dc
.printer
));
2630 /* Ensure that we can add an arbitrary number of fix-it hints to a
2631 rich_location, even if they are not consolidated. */
2634 test_one_liner_many_fixits_2 ()
2636 test_diagnostic_context dc
;
2637 location_t equals
= linemap_position_for_column (line_table
, 5);
2638 rich_location
richloc (line_table
, equals
);
2639 for (int i
= 0; i
< 19; i
++)
2641 location_t loc
= linemap_position_for_column (line_table
, i
* 2);
2642 richloc
.add_fixit_insert_before (loc
, "a");
2644 ASSERT_EQ (19, richloc
.get_num_fixit_hints ());
2645 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2647 " foo = bar.field;\n"
2649 "a a a a a a a a a a a a a a a a a a a\n",
2650 pp_formatted_text (dc
.printer
));
2653 /* Test of labeling the ranges within a rich_location. */
2656 test_one_liner_labels ()
2659 = make_location (linemap_position_for_column (line_table
, 1),
2660 linemap_position_for_column (line_table
, 1),
2661 linemap_position_for_column (line_table
, 3));
2663 = make_location (linemap_position_for_column (line_table
, 7),
2664 linemap_position_for_column (line_table
, 7),
2665 linemap_position_for_column (line_table
, 9));
2667 = make_location (linemap_position_for_column (line_table
, 11),
2668 linemap_position_for_column (line_table
, 11),
2669 linemap_position_for_column (line_table
, 15));
2671 /* Example where all the labels fit on one line. */
2673 text_range_label
label0 ("0");
2674 text_range_label
label1 ("1");
2675 text_range_label
label2 ("2");
2676 gcc_rich_location
richloc (foo
, &label0
);
2677 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
2678 richloc
.add_range (field
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
2681 test_diagnostic_context dc
;
2682 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2684 " foo = bar.field;\n"
2688 pp_formatted_text (dc
.printer
));
2691 /* Verify that we can disable label-printing. */
2693 test_diagnostic_context dc
;
2694 dc
.show_labels_p
= false;
2695 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2697 " foo = bar.field;\n"
2699 pp_formatted_text (dc
.printer
));
2703 /* Example where the labels need extra lines. */
2705 text_range_label
label0 ("label 0");
2706 text_range_label
label1 ("label 1");
2707 text_range_label
label2 ("label 2");
2708 gcc_rich_location
richloc (foo
, &label0
);
2709 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
2710 richloc
.add_range (field
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
2712 test_diagnostic_context dc
;
2713 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2715 " foo = bar.field;\n"
2721 pp_formatted_text (dc
.printer
));
2724 /* Example of boundary conditions: label 0 and 1 have just enough clearance,
2725 but label 1 just touches label 2. */
2727 text_range_label
label0 ("aaaaa");
2728 text_range_label
label1 ("bbbb");
2729 text_range_label
label2 ("c");
2730 gcc_rich_location
richloc (foo
, &label0
);
2731 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
2732 richloc
.add_range (field
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
2734 test_diagnostic_context dc
;
2735 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2737 " foo = bar.field;\n"
2742 pp_formatted_text (dc
.printer
));
2745 /* Example of out-of-order ranges (thus requiring a sort). */
2747 text_range_label
label0 ("0");
2748 text_range_label
label1 ("1");
2749 text_range_label
label2 ("2");
2750 gcc_rich_location
richloc (field
, &label0
);
2751 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
2752 richloc
.add_range (foo
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
2754 test_diagnostic_context dc
;
2755 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2757 " foo = bar.field;\n"
2761 pp_formatted_text (dc
.printer
));
2764 /* Ensure we don't ICE if multiple ranges with labels are on
2767 text_range_label
label0 ("label 0");
2768 text_range_label
label1 ("label 1");
2769 text_range_label
label2 ("label 2");
2770 gcc_rich_location
richloc (bar
, &label0
);
2771 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
2772 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
2774 test_diagnostic_context dc
;
2775 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2777 " foo = bar.field;\n"
2783 pp_formatted_text (dc
.printer
));
2786 /* Verify that a NULL result from range_label::get_text is
2787 handled gracefully. */
2789 text_range_label
label (NULL
);
2790 gcc_rich_location
richloc (bar
, &label
);
2792 test_diagnostic_context dc
;
2793 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2795 " foo = bar.field;\n"
2797 pp_formatted_text (dc
.printer
));
2800 /* TODO: example of formatted printing (needs to be in
2801 gcc-rich-location.c due to Makefile.in issues). */
2804 /* Run the various one-liner tests. */
2807 test_diagnostic_show_locus_one_liner (const line_table_case
&case_
)
2809 /* Create a tempfile and write some text to it.
2810 ....................0000000001111111.
2811 ....................1234567890123456. */
2812 const char *content
= "foo = bar.field;\n";
2813 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
2814 line_table_test
ltt (case_
);
2816 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 1);
2818 location_t line_end
= linemap_position_for_column (line_table
, 16);
2820 /* Don't attempt to run the tests if column data might be unavailable. */
2821 if (line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2824 ASSERT_STREQ (tmp
.get_filename (), LOCATION_FILE (line_end
));
2825 ASSERT_EQ (1, LOCATION_LINE (line_end
));
2826 ASSERT_EQ (16, LOCATION_COLUMN (line_end
));
2828 test_one_liner_simple_caret ();
2829 test_one_liner_caret_and_range ();
2830 test_one_liner_multiple_carets_and_ranges ();
2831 test_one_liner_fixit_insert_before ();
2832 test_one_liner_fixit_insert_after ();
2833 test_one_liner_fixit_remove ();
2834 test_one_liner_fixit_replace ();
2835 test_one_liner_fixit_replace_non_equal_range ();
2836 test_one_liner_fixit_replace_equal_secondary_range ();
2837 test_one_liner_fixit_validation_adhoc_locations ();
2838 test_one_liner_many_fixits_1 ();
2839 test_one_liner_many_fixits_2 ();
2840 test_one_liner_labels ();
2843 /* Verify that gcc_rich_location::add_location_if_nearby works. */
2846 test_add_location_if_nearby (const line_table_case
&case_
)
2848 /* Create a tempfile and write some text to it.
2849 ...000000000111111111122222222223333333333.
2850 ...123456789012345678901234567890123456789. */
2852 = ("struct same_line { double x; double y; ;\n" /* line 1. */
2853 "struct different_line\n" /* line 2. */
2855 " double x;\n" /* line 4. */
2856 " double y;\n" /* line 5. */
2857 ";\n"); /* line 6. */
2858 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
2859 line_table_test
ltt (case_
);
2861 const line_map_ordinary
*ord_map
2862 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
2863 tmp
.get_filename (), 0));
2865 linemap_line_start (line_table
, 1, 100);
2867 const location_t final_line_end
2868 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 7);
2870 /* Don't attempt to run the tests if column data might be unavailable. */
2871 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2874 /* Test of add_location_if_nearby on the same line as the
2875 primary location. */
2877 const location_t missing_close_brace_1_39
2878 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 39);
2879 const location_t matching_open_brace_1_18
2880 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 18);
2881 gcc_rich_location
richloc (missing_close_brace_1_39
);
2882 bool added
= richloc
.add_location_if_nearby (matching_open_brace_1_18
);
2883 ASSERT_TRUE (added
);
2884 ASSERT_EQ (2, richloc
.get_num_locations ());
2885 test_diagnostic_context dc
;
2886 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2888 " struct same_line { double x; double y; ;\n"
2890 pp_formatted_text (dc
.printer
));
2893 /* Test of add_location_if_nearby on a different line to the
2894 primary location. */
2896 const location_t missing_close_brace_6_1
2897 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 1);
2898 const location_t matching_open_brace_3_1
2899 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 1);
2900 gcc_rich_location
richloc (missing_close_brace_6_1
);
2901 bool added
= richloc
.add_location_if_nearby (matching_open_brace_3_1
);
2902 ASSERT_FALSE (added
);
2903 ASSERT_EQ (1, richloc
.get_num_locations ());
2907 /* Verify that we print fixits even if they only affect lines
2908 outside those covered by the ranges in the rich_location. */
2911 test_diagnostic_show_locus_fixit_lines (const line_table_case
&case_
)
2913 /* Create a tempfile and write some text to it.
2914 ...000000000111111111122222222223333333333.
2915 ...123456789012345678901234567890123456789. */
2917 = ("struct point { double x; double y; };\n" /* line 1. */
2918 "struct point origin = {x: 0.0,\n" /* line 2. */
2919 " y\n" /* line 3. */
2922 " : 0.0};\n"); /* line 6. */
2923 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
2924 line_table_test
ltt (case_
);
2926 const line_map_ordinary
*ord_map
2927 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
2928 tmp
.get_filename (), 0));
2930 linemap_line_start (line_table
, 1, 100);
2932 const location_t final_line_end
2933 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 36);
2935 /* Don't attempt to run the tests if column data might be unavailable. */
2936 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2939 /* A pair of tests for modernizing the initializers to C99-style. */
2941 /* The one-liner case (line 2). */
2943 test_diagnostic_context dc
;
2945 = linemap_position_for_line_and_column (line_table
, ord_map
, 2, 24);
2946 const location_t colon
2947 = linemap_position_for_line_and_column (line_table
, ord_map
, 2, 25);
2948 rich_location
richloc (line_table
, colon
);
2949 richloc
.add_fixit_insert_before (x
, ".");
2950 richloc
.add_fixit_replace (colon
, "=");
2951 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2953 " struct point origin = {x: 0.0,\n"
2956 pp_formatted_text (dc
.printer
));
2959 /* The multiline case. The caret for the rich_location is on line 6;
2960 verify that insertion fixit on line 3 is still printed (and that
2961 span starts are printed due to the gap between the span at line 3
2962 and that at line 6). */
2964 test_diagnostic_context dc
;
2966 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 24);
2967 const location_t colon
2968 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 25);
2969 rich_location
richloc (line_table
, colon
);
2970 richloc
.add_fixit_insert_before (y
, ".");
2971 richloc
.add_fixit_replace (colon
, "=");
2972 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2981 pp_formatted_text (dc
.printer
));
2984 /* As above, but verify the behavior of multiple line spans
2985 with line-numbering enabled. */
2988 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 24);
2989 const location_t colon
2990 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 25);
2991 rich_location
richloc (line_table
, colon
);
2992 richloc
.add_fixit_insert_before (y
, ".");
2993 richloc
.add_fixit_replace (colon
, "=");
2994 test_diagnostic_context dc
;
2995 dc
.show_line_numbers_p
= true;
2996 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3004 pp_formatted_text (dc
.printer
));
3009 /* Verify that fix-it hints are appropriately consolidated.
3011 If any fix-it hints in a rich_location involve locations beyond
3012 LINE_MAP_MAX_LOCATION_WITH_COLS, then we can't reliably apply
3013 the fix-it as a whole, so there should be none.
3015 Otherwise, verify that consecutive "replace" and "remove" fix-its
3016 are merged, and that other fix-its remain separate. */
3019 test_fixit_consolidation (const line_table_case
&case_
)
3021 line_table_test
ltt (case_
);
3023 linemap_add (line_table
, LC_ENTER
, false, "test.c", 1);
3025 const location_t c10
= linemap_position_for_column (line_table
, 10);
3026 const location_t c15
= linemap_position_for_column (line_table
, 15);
3027 const location_t c16
= linemap_position_for_column (line_table
, 16);
3028 const location_t c17
= linemap_position_for_column (line_table
, 17);
3029 const location_t c20
= linemap_position_for_column (line_table
, 20);
3030 const location_t c21
= linemap_position_for_column (line_table
, 21);
3031 const location_t caret
= c10
;
3033 /* Insert + insert. */
3035 rich_location
richloc (line_table
, caret
);
3036 richloc
.add_fixit_insert_before (c10
, "foo");
3037 richloc
.add_fixit_insert_before (c15
, "bar");
3039 if (c15
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3040 /* Bogus column info for 2nd fixit, so no fixits. */
3041 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
3043 /* They should not have been merged. */
3044 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
3047 /* Insert + replace. */
3049 rich_location
richloc (line_table
, caret
);
3050 richloc
.add_fixit_insert_before (c10
, "foo");
3051 richloc
.add_fixit_replace (source_range::from_locations (c15
, c17
),
3054 if (c17
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3055 /* Bogus column info for 2nd fixit, so no fixits. */
3056 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
3058 /* They should not have been merged. */
3059 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
3062 /* Replace + non-consecutive insert. */
3064 rich_location
richloc (line_table
, caret
);
3065 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
3067 richloc
.add_fixit_insert_before (c17
, "foo");
3069 if (c17
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3070 /* Bogus column info for 2nd fixit, so no fixits. */
3071 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
3073 /* They should not have been merged. */
3074 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
3077 /* Replace + non-consecutive replace. */
3079 rich_location
richloc (line_table
, caret
);
3080 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
3082 richloc
.add_fixit_replace (source_range::from_locations (c17
, c20
),
3085 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3086 /* Bogus column info for 2nd fixit, so no fixits. */
3087 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
3089 /* They should not have been merged. */
3090 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
3093 /* Replace + consecutive replace. */
3095 rich_location
richloc (line_table
, caret
);
3096 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
3098 richloc
.add_fixit_replace (source_range::from_locations (c16
, c20
),
3101 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3102 /* Bogus column info for 2nd fixit, so no fixits. */
3103 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
3106 /* They should have been merged into a single "replace". */
3107 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3108 const fixit_hint
*hint
= richloc
.get_fixit_hint (0);
3109 ASSERT_STREQ ("foobar", hint
->get_string ());
3110 ASSERT_EQ (c10
, hint
->get_start_loc ());
3111 ASSERT_EQ (c21
, hint
->get_next_loc ());
3115 /* Replace + consecutive removal. */
3117 rich_location
richloc (line_table
, caret
);
3118 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
3120 richloc
.add_fixit_remove (source_range::from_locations (c16
, c20
));
3122 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3123 /* Bogus column info for 2nd fixit, so no fixits. */
3124 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
3127 /* They should have been merged into a single replace, with the
3128 range extended to cover that of the removal. */
3129 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3130 const fixit_hint
*hint
= richloc
.get_fixit_hint (0);
3131 ASSERT_STREQ ("foo", hint
->get_string ());
3132 ASSERT_EQ (c10
, hint
->get_start_loc ());
3133 ASSERT_EQ (c21
, hint
->get_next_loc ());
3137 /* Consecutive removals. */
3139 rich_location
richloc (line_table
, caret
);
3140 richloc
.add_fixit_remove (source_range::from_locations (c10
, c15
));
3141 richloc
.add_fixit_remove (source_range::from_locations (c16
, c20
));
3143 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3144 /* Bogus column info for 2nd fixit, so no fixits. */
3145 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
3148 /* They should have been merged into a single "replace-with-empty". */
3149 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3150 const fixit_hint
*hint
= richloc
.get_fixit_hint (0);
3151 ASSERT_STREQ ("", hint
->get_string ());
3152 ASSERT_EQ (c10
, hint
->get_start_loc ());
3153 ASSERT_EQ (c21
, hint
->get_next_loc ());
3158 /* Verify that the line_corrections machinery correctly prints
3159 overlapping fixit-hints. */
3162 test_overlapped_fixit_printing (const line_table_case
&case_
)
3164 /* Create a tempfile and write some text to it.
3165 ...000000000111111111122222222223333333333.
3166 ...123456789012345678901234567890123456789. */
3168 = (" foo *f = (foo *)ptr->field;\n");
3169 temp_source_file
tmp (SELFTEST_LOCATION
, ".C", content
);
3170 line_table_test
ltt (case_
);
3172 const line_map_ordinary
*ord_map
3173 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
3174 tmp
.get_filename (), 0));
3176 linemap_line_start (line_table
, 1, 100);
3178 const location_t final_line_end
3179 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 36);
3181 /* Don't attempt to run the tests if column data might be unavailable. */
3182 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3185 /* A test for converting a C-style cast to a C++-style cast. */
3186 const location_t open_paren
3187 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 12);
3188 const location_t close_paren
3189 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 18);
3190 const location_t expr_start
3191 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 19);
3192 const location_t expr_finish
3193 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 28);
3194 const location_t expr
= make_location (expr_start
, expr_start
, expr_finish
);
3196 /* Various examples of fix-it hints that aren't themselves consolidated,
3197 but for which the *printing* may need consolidation. */
3199 /* Example where 3 fix-it hints are printed as one. */
3201 test_diagnostic_context dc
;
3202 rich_location
richloc (line_table
, expr
);
3203 richloc
.add_fixit_replace (open_paren
, "const_cast<");
3204 richloc
.add_fixit_replace (close_paren
, "> (");
3205 richloc
.add_fixit_insert_after (")");
3207 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3209 " foo *f = (foo *)ptr->field;\n"
3211 " -----------------\n"
3212 " const_cast<foo *> (ptr->field)\n",
3213 pp_formatted_text (dc
.printer
));
3215 /* Unit-test the line_corrections machinery. */
3216 ASSERT_EQ (3, richloc
.get_num_fixit_hints ());
3217 const fixit_hint
*hint_0
= richloc
.get_fixit_hint (0);
3218 ASSERT_EQ (column_range (12, 12), get_affected_columns (hint_0
));
3219 ASSERT_EQ (column_range (12, 22), get_printed_columns (hint_0
));
3220 const fixit_hint
*hint_1
= richloc
.get_fixit_hint (1);
3221 ASSERT_EQ (column_range (18, 18), get_affected_columns (hint_1
));
3222 ASSERT_EQ (column_range (18, 20), get_printed_columns (hint_1
));
3223 const fixit_hint
*hint_2
= richloc
.get_fixit_hint (2);
3224 ASSERT_EQ (column_range (29, 28), get_affected_columns (hint_2
));
3225 ASSERT_EQ (column_range (29, 29), get_printed_columns (hint_2
));
3227 /* Add each hint in turn to a line_corrections instance,
3228 and verify that they are consolidated into one correction instance
3230 line_corrections
lc (tmp
.get_filename (), 1);
3232 /* The first replace hint by itself. */
3233 lc
.add_hint (hint_0
);
3234 ASSERT_EQ (1, lc
.m_corrections
.length ());
3235 ASSERT_EQ (column_range (12, 12), lc
.m_corrections
[0]->m_affected_columns
);
3236 ASSERT_EQ (column_range (12, 22), lc
.m_corrections
[0]->m_printed_columns
);
3237 ASSERT_STREQ ("const_cast<", lc
.m_corrections
[0]->m_text
);
3239 /* After the second replacement hint, they are printed together
3240 as a replacement (along with the text between them). */
3241 lc
.add_hint (hint_1
);
3242 ASSERT_EQ (1, lc
.m_corrections
.length ());
3243 ASSERT_STREQ ("const_cast<foo *> (", lc
.m_corrections
[0]->m_text
);
3244 ASSERT_EQ (column_range (12, 18), lc
.m_corrections
[0]->m_affected_columns
);
3245 ASSERT_EQ (column_range (12, 30), lc
.m_corrections
[0]->m_printed_columns
);
3247 /* After the final insertion hint, they are all printed together
3248 as a replacement (along with the text between them). */
3249 lc
.add_hint (hint_2
);
3250 ASSERT_STREQ ("const_cast<foo *> (ptr->field)",
3251 lc
.m_corrections
[0]->m_text
);
3252 ASSERT_EQ (1, lc
.m_corrections
.length ());
3253 ASSERT_EQ (column_range (12, 28), lc
.m_corrections
[0]->m_affected_columns
);
3254 ASSERT_EQ (column_range (12, 41), lc
.m_corrections
[0]->m_printed_columns
);
3257 /* Example where two are consolidated during printing. */
3259 test_diagnostic_context dc
;
3260 rich_location
richloc (line_table
, expr
);
3261 richloc
.add_fixit_replace (open_paren
, "CAST (");
3262 richloc
.add_fixit_replace (close_paren
, ") (");
3263 richloc
.add_fixit_insert_after (")");
3265 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3267 " foo *f = (foo *)ptr->field;\n"
3272 pp_formatted_text (dc
.printer
));
3275 /* Example where none are consolidated during printing. */
3277 test_diagnostic_context dc
;
3278 rich_location
richloc (line_table
, expr
);
3279 richloc
.add_fixit_replace (open_paren
, "CST (");
3280 richloc
.add_fixit_replace (close_paren
, ") (");
3281 richloc
.add_fixit_insert_after (")");
3283 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3285 " foo *f = (foo *)ptr->field;\n"
3290 pp_formatted_text (dc
.printer
));
3293 /* Example of deletion fix-it hints. */
3295 test_diagnostic_context dc
;
3296 rich_location
richloc (line_table
, expr
);
3297 richloc
.add_fixit_insert_before (open_paren
, "(bar *)");
3298 source_range victim
= {open_paren
, close_paren
};
3299 richloc
.add_fixit_remove (victim
);
3301 /* This case is actually handled by fixit-consolidation,
3302 rather than by line_corrections. */
3303 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3305 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3307 " foo *f = (foo *)ptr->field;\n"
3311 pp_formatted_text (dc
.printer
));
3314 /* Example of deletion fix-it hints that would overlap. */
3316 test_diagnostic_context dc
;
3317 rich_location
richloc (line_table
, expr
);
3318 richloc
.add_fixit_insert_before (open_paren
, "(longer *)");
3319 source_range victim
= {expr_start
, expr_finish
};
3320 richloc
.add_fixit_remove (victim
);
3322 /* These fixits are not consolidated. */
3323 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
3325 /* But the corrections are. */
3326 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3328 " foo *f = (foo *)ptr->field;\n"
3330 " -----------------\n"
3331 " (longer *)(foo *)\n",
3332 pp_formatted_text (dc
.printer
));
3335 /* Example of insertion fix-it hints that would overlap. */
3337 test_diagnostic_context dc
;
3338 rich_location
richloc (line_table
, expr
);
3339 richloc
.add_fixit_insert_before (open_paren
, "LONGER THAN THE CAST");
3340 richloc
.add_fixit_insert_after (close_paren
, "TEST");
3342 /* The first insertion is long enough that if printed naively,
3343 it would overlap with the second.
3344 Verify that they are printed as a single replacement. */
3345 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3347 " foo *f = (foo *)ptr->field;\n"
3350 " LONGER THAN THE CAST(foo *)TEST\n",
3351 pp_formatted_text (dc
.printer
));
3355 /* Verify that the line_corrections machinery correctly prints
3356 overlapping fixit-hints that have been added in the wrong
3358 Adapted from PR c/81405 seen on gcc.dg/init-excess-1.c*/
3361 test_overlapped_fixit_printing_2 (const line_table_case
&case_
)
3363 /* Create a tempfile and write some text to it.
3364 ...000000000111111111122222222223333333333.
3365 ...123456789012345678901234567890123456789. */
3367 = ("int a5[][0][0] = { 1, 2 };\n");
3368 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
3369 line_table_test
ltt (case_
);
3371 const line_map_ordinary
*ord_map
3372 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
3373 tmp
.get_filename (), 0));
3375 linemap_line_start (line_table
, 1, 100);
3377 const location_t final_line_end
3378 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 100);
3380 /* Don't attempt to run the tests if column data might be unavailable. */
3381 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3384 const location_t col_1
3385 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 1);
3386 const location_t col_20
3387 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 20);
3388 const location_t col_21
3389 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 21);
3390 const location_t col_23
3391 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 23);
3392 const location_t col_25
3393 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 25);
3395 /* Two insertions, in the wrong order. */
3397 rich_location
richloc (line_table
, col_20
);
3398 richloc
.add_fixit_insert_before (col_23
, "{");
3399 richloc
.add_fixit_insert_before (col_21
, "}");
3401 /* These fixits should be accepted; they can't be consolidated. */
3402 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
3403 const fixit_hint
*hint_0
= richloc
.get_fixit_hint (0);
3404 ASSERT_EQ (column_range (23, 22), get_affected_columns (hint_0
));
3405 ASSERT_EQ (column_range (23, 23), get_printed_columns (hint_0
));
3406 const fixit_hint
*hint_1
= richloc
.get_fixit_hint (1);
3407 ASSERT_EQ (column_range (21, 20), get_affected_columns (hint_1
));
3408 ASSERT_EQ (column_range (21, 21), get_printed_columns (hint_1
));
3410 /* Verify that they're printed correctly. */
3411 test_diagnostic_context dc
;
3412 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3414 " int a5[][0][0] = { 1, 2 };\n"
3417 pp_formatted_text (dc
.printer
));
3420 /* Various overlapping insertions, some occurring "out of order"
3421 (reproducing the fix-it hints from PR c/81405). */
3423 test_diagnostic_context dc
;
3424 rich_location
richloc (line_table
, col_20
);
3426 richloc
.add_fixit_insert_before (col_20
, "{{");
3427 richloc
.add_fixit_insert_before (col_21
, "}}");
3428 richloc
.add_fixit_insert_before (col_23
, "{");
3429 richloc
.add_fixit_insert_before (col_21
, "}");
3430 richloc
.add_fixit_insert_before (col_23
, "{{");
3431 richloc
.add_fixit_insert_before (col_25
, "}");
3432 richloc
.add_fixit_insert_before (col_21
, "}");
3433 richloc
.add_fixit_insert_before (col_1
, "{");
3434 richloc
.add_fixit_insert_before (col_25
, "}");
3435 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3437 " int a5[][0][0] = { 1, 2 };\n"
3440 " {{1}}}}, {{{2 }}\n",
3441 pp_formatted_text (dc
.printer
));
3445 /* Insertion fix-it hint: adding a "break;" on a line by itself. */
3448 test_fixit_insert_containing_newline (const line_table_case
&case_
)
3450 /* Create a tempfile and write some text to it.
3451 .........................0000000001111111.
3452 .........................1234567890123456. */
3453 const char *old_content
= (" case 'a':\n" /* line 1. */
3454 " x = a;\n" /* line 2. */
3455 " case 'b':\n" /* line 3. */
3456 " x = b;\n");/* line 4. */
3458 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
3459 line_table_test
ltt (case_
);
3460 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 3);
3462 location_t case_start
= linemap_position_for_column (line_table
, 5);
3463 location_t case_finish
= linemap_position_for_column (line_table
, 13);
3464 location_t case_loc
= make_location (case_start
, case_start
, case_finish
);
3465 location_t line_start
= linemap_position_for_column (line_table
, 1);
3467 if (case_finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3470 /* Add a "break;" on a line by itself before line 3 i.e. before
3471 column 1 of line 3. */
3473 rich_location
richloc (line_table
, case_loc
);
3474 richloc
.add_fixit_insert_before (line_start
, " break;\n");
3476 /* Without line numbers. */
3478 test_diagnostic_context dc
;
3479 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3485 pp_formatted_text (dc
.printer
));
3488 /* With line numbers. */
3490 test_diagnostic_context dc
;
3491 dc
.show_line_numbers_p
= true;
3492 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3498 pp_formatted_text (dc
.printer
));
3502 /* Verify that attempts to add text with a newline fail when the
3503 insertion point is *not* at the start of a line. */
3505 rich_location
richloc (line_table
, case_loc
);
3506 richloc
.add_fixit_insert_before (case_start
, "break;\n");
3507 ASSERT_TRUE (richloc
.seen_impossible_fixit_p ());
3508 test_diagnostic_context dc
;
3509 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3513 pp_formatted_text (dc
.printer
));
3517 /* Insertion fix-it hint: adding a "#include <stdio.h>\n" to the top
3518 of the file, where the fix-it is printed in a different line-span
3519 to the primary range of the diagnostic. */
3522 test_fixit_insert_containing_newline_2 (const line_table_case
&case_
)
3524 /* Create a tempfile and write some text to it.
3525 .........................0000000001111111.
3526 .........................1234567890123456. */
3527 const char *old_content
= ("test (int ch)\n" /* line 1. */
3529 " putchar (ch);\n" /* line 3. */
3530 "}\n"); /* line 4. */
3532 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
3533 line_table_test
ltt (case_
);
3535 const line_map_ordinary
*ord_map
= linemap_check_ordinary
3536 (linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 0));
3537 linemap_line_start (line_table
, 1, 100);
3539 /* The primary range is the "putchar" token. */
3540 location_t putchar_start
3541 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 2);
3542 location_t putchar_finish
3543 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 8);
3544 location_t putchar_loc
3545 = make_location (putchar_start
, putchar_start
, putchar_finish
);
3546 rich_location
richloc (line_table
, putchar_loc
);
3548 /* Add a "#include <stdio.h>" on a line by itself at the top of the file. */
3549 location_t file_start
3550 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 1);
3551 richloc
.add_fixit_insert_before (file_start
, "#include <stdio.h>\n");
3553 if (putchar_finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3557 test_diagnostic_context dc
;
3558 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3561 "+#include <stdio.h>\n"
3566 pp_formatted_text (dc
.printer
));
3569 /* With line-numbering, the line spans are close enough to be
3570 consolidated, since it makes little sense to skip line 2. */
3572 test_diagnostic_context dc
;
3573 dc
.show_line_numbers_p
= true;
3574 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3576 " +++ |+#include <stdio.h>\n"
3577 " 1 | test (int ch)\n"
3579 " 3 | putchar (ch);\n"
3581 pp_formatted_text (dc
.printer
));
3585 /* Replacement fix-it hint containing a newline.
3586 This will fail, as newlines are only supported when inserting at the
3587 beginning of a line. */
3590 test_fixit_replace_containing_newline (const line_table_case
&case_
)
3592 /* Create a tempfile and write some text to it.
3593 .........................0000000001111.
3594 .........................1234567890123. */
3595 const char *old_content
= "foo = bar ();\n";
3597 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
3598 line_table_test
ltt (case_
);
3599 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 1);
3601 /* Replace the " = " with "\n = ", as if we were reformatting an
3602 overly long line. */
3603 location_t start
= linemap_position_for_column (line_table
, 4);
3604 location_t finish
= linemap_position_for_column (line_table
, 6);
3605 location_t loc
= linemap_position_for_column (line_table
, 13);
3606 rich_location
richloc (line_table
, loc
);
3607 source_range range
= source_range::from_locations (start
, finish
);
3608 richloc
.add_fixit_replace (range
, "\n =");
3610 /* Arbitrary newlines are not yet supported within fix-it hints, so
3611 the fix-it should not be displayed. */
3612 ASSERT_TRUE (richloc
.seen_impossible_fixit_p ());
3614 if (finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3617 test_diagnostic_context dc
;
3618 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3622 pp_formatted_text (dc
.printer
));
3625 /* Fix-it hint, attempting to delete a newline.
3626 This will fail, as we currently only support fix-it hints that
3627 affect one line at a time. */
3630 test_fixit_deletion_affecting_newline (const line_table_case
&case_
)
3632 /* Create a tempfile and write some text to it.
3633 ..........................0000000001111.
3634 ..........................1234567890123. */
3635 const char *old_content
= ("foo = bar (\n"
3638 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
3639 line_table_test
ltt (case_
);
3640 const line_map_ordinary
*ord_map
= linemap_check_ordinary
3641 (linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 0));
3642 linemap_line_start (line_table
, 1, 100);
3644 /* Attempt to delete the " (\n...)". */
3646 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 10);
3648 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 11);
3650 = linemap_position_for_line_and_column (line_table
, ord_map
, 2, 7);
3651 location_t loc
= make_location (caret
, start
, finish
);
3652 rich_location
richloc (line_table
, loc
);
3653 richloc
. add_fixit_remove ();
3655 /* Fix-it hints that affect more than one line are not yet supported, so
3656 the fix-it should not be displayed. */
3657 ASSERT_TRUE (richloc
.seen_impossible_fixit_p ());
3659 if (finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3662 test_diagnostic_context dc
;
3663 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3669 pp_formatted_text (dc
.printer
));
3672 /* Verify that line numbers are correctly printed for the case of
3673 a multiline range in which the width of the line numbers changes
3674 (e.g. from "9" to "10"). */
3677 test_line_numbers_multiline_range ()
3679 /* Create a tempfile and write some text to it. */
3681 for (int i
= 0; i
< 20; i
++)
3682 /* .........0000000001111111.
3683 .............1234567890123456. */
3684 pp_printf (&pp
, "this is line %i\n", i
+ 1);
3685 temp_source_file
tmp (SELFTEST_LOCATION
, ".txt", pp_formatted_text (&pp
));
3686 line_table_test ltt
;
3688 const line_map_ordinary
*ord_map
= linemap_check_ordinary
3689 (linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 0));
3690 linemap_line_start (line_table
, 1, 100);
3692 /* Create a multi-line location, starting at the "line" of line 9, with
3693 a caret on the "is" of line 10, finishing on the "this" line 11. */
3696 = linemap_position_for_line_and_column (line_table
, ord_map
, 9, 9);
3698 = linemap_position_for_line_and_column (line_table
, ord_map
, 10, 6);
3700 = linemap_position_for_line_and_column (line_table
, ord_map
, 11, 4);
3701 location_t loc
= make_location (caret
, start
, finish
);
3703 test_diagnostic_context dc
;
3704 dc
.show_line_numbers_p
= true;
3705 dc
.min_margin_width
= 0;
3706 gcc_rich_location
richloc (loc
);
3707 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3709 " 9 | this is line 9\n"
3711 "10 | this is line 10\n"
3712 " | ~~~~~^~~~~~~~~~\n"
3713 "11 | this is line 11\n"
3715 pp_formatted_text (dc
.printer
));
3718 /* Run all of the selftests within this file. */
3721 diagnostic_show_locus_c_tests ()
3725 test_layout_range_for_single_point ();
3726 test_layout_range_for_single_line ();
3727 test_layout_range_for_multiple_lines ();
3729 test_get_line_width_without_trailing_whitespace ();
3731 test_diagnostic_show_locus_unknown_location ();
3733 for_each_line_table_case (test_diagnostic_show_locus_one_liner
);
3734 for_each_line_table_case (test_add_location_if_nearby
);
3735 for_each_line_table_case (test_diagnostic_show_locus_fixit_lines
);
3736 for_each_line_table_case (test_fixit_consolidation
);
3737 for_each_line_table_case (test_overlapped_fixit_printing
);
3738 for_each_line_table_case (test_overlapped_fixit_printing_2
);
3739 for_each_line_table_case (test_fixit_insert_containing_newline
);
3740 for_each_line_table_case (test_fixit_insert_containing_newline_2
);
3741 for_each_line_table_case (test_fixit_replace_containing_newline
);
3742 for_each_line_table_case (test_fixit_deletion_affecting_newline
);
3744 test_line_numbers_multiline_range ();
3747 } // namespace selftest
3749 #endif /* #if CHECKING_P */
3752 # pragma GCC diagnostic pop