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). */
170 line_span (linenum_type first_line
, linenum_type last_line
)
171 : m_first_line (first_line
), m_last_line (last_line
)
173 gcc_assert (first_line
<= last_line
);
175 linenum_type
get_first_line () const { return m_first_line
; }
176 linenum_type
get_last_line () const { return m_last_line
; }
178 bool contains_line_p (linenum_type line
) const
180 return line
>= m_first_line
&& line
<= m_last_line
;
183 static int comparator (const void *p1
, const void *p2
)
185 const line_span
*ls1
= (const line_span
*)p1
;
186 const line_span
*ls2
= (const line_span
*)p2
;
187 int first_line_cmp
= compare (ls1
->m_first_line
, ls2
->m_first_line
);
189 return first_line_cmp
;
190 return compare (ls1
->m_last_line
, ls2
->m_last_line
);
193 linenum_type m_first_line
;
194 linenum_type m_last_line
;
199 /* Selftests for line_span. */
204 line_span
line_one (1, 1);
205 ASSERT_EQ (1, line_one
.get_first_line ());
206 ASSERT_EQ (1, line_one
.get_last_line ());
207 ASSERT_FALSE (line_one
.contains_line_p (0));
208 ASSERT_TRUE (line_one
.contains_line_p (1));
209 ASSERT_FALSE (line_one
.contains_line_p (2));
211 line_span
lines_1_to_3 (1, 3);
212 ASSERT_EQ (1, lines_1_to_3
.get_first_line ());
213 ASSERT_EQ (3, lines_1_to_3
.get_last_line ());
214 ASSERT_TRUE (lines_1_to_3
.contains_line_p (1));
215 ASSERT_TRUE (lines_1_to_3
.contains_line_p (3));
217 ASSERT_EQ (0, line_span::comparator (&line_one
, &line_one
));
218 ASSERT_GT (line_span::comparator (&lines_1_to_3
, &line_one
), 0);
219 ASSERT_LT (line_span::comparator (&line_one
, &lines_1_to_3
), 0);
221 /* A linenum > 2^31. */
222 const linenum_type LARGEST_LINE
= 0xffffffff;
223 line_span
largest_line (LARGEST_LINE
, LARGEST_LINE
);
224 ASSERT_EQ (LARGEST_LINE
, largest_line
.get_first_line ());
225 ASSERT_EQ (LARGEST_LINE
, largest_line
.get_last_line ());
227 ASSERT_GT (line_span::comparator (&largest_line
, &line_one
), 0);
228 ASSERT_LT (line_span::comparator (&line_one
, &largest_line
), 0);
231 #endif /* #if CHECKING_P */
233 /* A class to control the overall layout when printing a diagnostic.
235 The layout is determined within the constructor.
236 It is then printed by repeatedly calling the "print_source_line",
237 "print_annotation_line" and "print_any_fixits" methods.
239 We assume we have disjoint ranges. */
244 layout (diagnostic_context
*context
,
245 rich_location
*richloc
,
246 diagnostic_t diagnostic_kind
);
248 bool maybe_add_location_range (const location_range
*loc_range
,
249 unsigned original_idx
,
250 bool restrict_to_current_line_spans
);
252 int get_num_line_spans () const { return m_line_spans
.length (); }
253 const line_span
*get_line_span (int idx
) const { return &m_line_spans
[idx
]; }
255 void print_gap_in_line_numbering ();
256 bool print_heading_for_line_span_index_p (int line_span_idx
) const;
258 expanded_location
get_expanded_location (const line_span
*) const;
260 void print_line (linenum_type row
);
263 bool will_show_line_p (linenum_type row
) const;
264 void print_leading_fixits (linenum_type row
);
265 void print_source_line (linenum_type row
, const char *line
, int line_width
,
266 line_bounds
*lbounds_out
);
267 bool should_print_annotation_line_p (linenum_type row
) const;
268 void start_annotation_line (char margin_char
= ' ') const;
269 void print_annotation_line (linenum_type row
, const line_bounds lbounds
);
270 void print_any_labels (linenum_type row
);
271 void print_trailing_fixits (linenum_type row
);
273 bool annotation_line_showed_range_p (linenum_type line
, int start_column
,
274 int finish_column
) const;
275 void show_ruler (int max_column
) const;
277 bool validate_fixit_hint_p (const fixit_hint
*hint
);
279 void calculate_line_spans ();
281 void print_newline ();
284 get_state_at_point (/* Inputs. */
285 linenum_type row
, int column
,
286 int first_non_ws
, int last_non_ws
,
288 point_state
*out_state
);
291 get_x_bound_for_row (linenum_type row
, int caret_column
,
295 move_to_column (int *column
, int dest_column
, bool add_left_margin
);
298 diagnostic_context
*m_context
;
299 pretty_printer
*m_pp
;
300 location_t m_primary_loc
;
301 expanded_location m_exploc
;
302 colorizer m_colorizer
;
303 bool m_colorize_source_p
;
304 bool m_show_labels_p
;
305 bool m_show_line_numbers_p
;
306 auto_vec
<layout_range
> m_layout_ranges
;
307 auto_vec
<const fixit_hint
*> m_fixit_hints
;
308 auto_vec
<line_span
> m_line_spans
;
313 /* Implementation of "class colorizer". */
315 /* The constructor for "colorizer". Lookup and store color codes for the
316 different kinds of things we might need to print. */
318 colorizer::colorizer (diagnostic_context
*context
,
319 diagnostic_t diagnostic_kind
) :
321 m_diagnostic_kind (diagnostic_kind
),
322 m_current_state (STATE_NORMAL_TEXT
)
324 m_range1
= get_color_by_name ("range1");
325 m_range2
= get_color_by_name ("range2");
326 m_fixit_insert
= get_color_by_name ("fixit-insert");
327 m_fixit_delete
= get_color_by_name ("fixit-delete");
328 m_stop_color
= colorize_stop (pp_show_color (context
->printer
));
331 /* The destructor for "colorize". If colorization is on, print a code to
334 colorizer::~colorizer ()
336 finish_state (m_current_state
);
339 /* Update state, printing color codes if necessary if there's a state
343 colorizer::set_state (int new_state
)
345 if (m_current_state
!= new_state
)
347 finish_state (m_current_state
);
348 m_current_state
= new_state
;
349 begin_state (new_state
);
353 /* Turn on any colorization for STATE. */
356 colorizer::begin_state (int state
)
360 case STATE_NORMAL_TEXT
:
363 case STATE_FIXIT_INSERT
:
364 pp_string (m_context
->printer
, m_fixit_insert
);
367 case STATE_FIXIT_DELETE
:
368 pp_string (m_context
->printer
, m_fixit_delete
);
372 /* Make range 0 be the same color as the "kind" text
373 (error vs warning vs note). */
376 colorize_start (pp_show_color (m_context
->printer
),
377 diagnostic_get_color_for_kind (m_diagnostic_kind
)));
381 pp_string (m_context
->printer
, m_range1
);
385 pp_string (m_context
->printer
, m_range2
);
389 /* For ranges beyond 2, alternate between color 1 and color 2. */
391 gcc_assert (state
> 2);
392 pp_string (m_context
->printer
,
393 state
% 2 ? m_range1
: m_range2
);
399 /* Turn off any colorization for STATE. */
402 colorizer::finish_state (int state
)
404 if (state
!= STATE_NORMAL_TEXT
)
405 pp_string (m_context
->printer
, m_stop_color
);
408 /* Get the color code for NAME (or the empty string if
409 colorization is disabled). */
412 colorizer::get_color_by_name (const char *name
)
414 return colorize_start (pp_show_color (m_context
->printer
), name
);
417 /* Implementation of class layout_range. */
419 /* The constructor for class layout_range.
420 Initialize various layout_point fields from expanded_location
421 equivalents; we've already filtered on file. */
423 layout_range::layout_range (const expanded_location
*start_exploc
,
424 const expanded_location
*finish_exploc
,
425 enum range_display_kind range_display_kind
,
426 const expanded_location
*caret_exploc
,
427 unsigned original_idx
,
428 const range_label
*label
)
429 : m_start (*start_exploc
),
430 m_finish (*finish_exploc
),
431 m_range_display_kind (range_display_kind
),
432 m_caret (*caret_exploc
),
433 m_original_idx (original_idx
),
438 /* Is (column, row) within the given range?
439 We've already filtered on the file.
441 Ranges are closed (both limits are within the range).
443 Example A: a single-line range:
444 start: (col=22, line=2)
445 finish: (col=38, line=2)
447 |00000011111111112222222222333333333344444444444
448 |34567890123456789012345678901234567890123456789
449 --+-----------------------------------------------
450 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
451 02|bbbbbbbbbbbbbbbbbbbSwwwwwwwwwwwwwwwFaaaaaaaaaaa
452 03|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
454 Example B: a multiline range with
455 start: (col=14, line=3)
456 finish: (col=08, line=5)
458 |00000011111111112222222222333333333344444444444
459 |34567890123456789012345678901234567890123456789
460 --+-----------------------------------------------
461 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
462 02|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
463 03|bbbbbbbbbbbSwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
464 04|wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
465 05|wwwwwFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
466 06|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
467 --+-----------------------------------------------
470 - 'b' indicates a point *before* the range
471 - 'S' indicates the start of the range
472 - 'w' indicates a point within the range
473 - 'F' indicates the finish of the range (which is
475 - 'a' indicates a subsequent point *after* the range. */
478 layout_range::contains_point (linenum_type row
, int column
) const
480 gcc_assert (m_start
.m_line
<= m_finish
.m_line
);
481 /* ...but the equivalent isn't true for the columns;
482 consider example B in the comment above. */
484 if (row
< m_start
.m_line
)
485 /* Points before the first line of the range are
486 outside it (corresponding to line 01 in example A
487 and lines 01 and 02 in example B above). */
490 if (row
== m_start
.m_line
)
491 /* On same line as start of range (corresponding
492 to line 02 in example A and line 03 in example B). */
494 if (column
< m_start
.m_column
)
495 /* Points on the starting line of the range, but
496 before the column in which it begins. */
499 if (row
< m_finish
.m_line
)
500 /* This is a multiline range; the point
501 is within it (corresponds to line 03 in example B
502 from column 14 onwards) */
506 /* This is a single-line range. */
507 gcc_assert (row
== m_finish
.m_line
);
508 return column
<= m_finish
.m_column
;
512 /* The point is in a line beyond that containing the
513 start of the range: lines 03 onwards in example A,
514 and lines 04 onwards in example B. */
515 gcc_assert (row
> m_start
.m_line
);
517 if (row
> m_finish
.m_line
)
518 /* The point is beyond the final line of the range
519 (lines 03 onwards in example A, and lines 06 onwards
523 if (row
< m_finish
.m_line
)
525 /* The point is in a line that's fully within a multiline
526 range (e.g. line 04 in example B). */
527 gcc_assert (m_start
.m_line
< m_finish
.m_line
);
531 gcc_assert (row
== m_finish
.m_line
);
533 return column
<= m_finish
.m_column
;
536 /* Does this layout_range contain any part of line ROW? */
539 layout_range::intersects_line_p (linenum_type row
) const
541 gcc_assert (m_start
.m_line
<= m_finish
.m_line
);
542 if (row
< m_start
.m_line
)
544 if (row
> m_finish
.m_line
)
551 /* A helper function for testing layout_range. */
554 make_range (int start_line
, int start_col
, int end_line
, int end_col
)
556 const expanded_location start_exploc
557 = {"test.c", start_line
, start_col
, NULL
, false};
558 const expanded_location finish_exploc
559 = {"test.c", end_line
, end_col
, NULL
, false};
560 return layout_range (&start_exploc
, &finish_exploc
, SHOW_RANGE_WITHOUT_CARET
,
561 &start_exploc
, 0, NULL
);
564 /* Selftests for layout_range::contains_point and
565 layout_range::intersects_line_p. */
567 /* Selftest for layout_range, where the layout_range
568 is a range with start==end i.e. a single point. */
571 test_layout_range_for_single_point ()
573 layout_range point
= make_range (7, 10, 7, 10);
575 /* Tests for layout_range::contains_point. */
577 /* Before the line. */
578 ASSERT_FALSE (point
.contains_point (6, 1));
580 /* On the line, but before start. */
581 ASSERT_FALSE (point
.contains_point (7, 9));
584 ASSERT_TRUE (point
.contains_point (7, 10));
586 /* On the line, after the point. */
587 ASSERT_FALSE (point
.contains_point (7, 11));
589 /* After the line. */
590 ASSERT_FALSE (point
.contains_point (8, 1));
592 /* Tests for layout_range::intersects_line_p. */
593 ASSERT_FALSE (point
.intersects_line_p (6));
594 ASSERT_TRUE (point
.intersects_line_p (7));
595 ASSERT_FALSE (point
.intersects_line_p (8));
598 /* Selftest for layout_range, where the layout_range
599 is the single-line range shown as "Example A" above. */
602 test_layout_range_for_single_line ()
604 layout_range example_a
= make_range (2, 22, 2, 38);
606 /* Tests for layout_range::contains_point. */
608 /* Before the line. */
609 ASSERT_FALSE (example_a
.contains_point (1, 1));
611 /* On the line, but before start. */
612 ASSERT_FALSE (example_a
.contains_point (2, 21));
614 /* On the line, at the start. */
615 ASSERT_TRUE (example_a
.contains_point (2, 22));
617 /* On the line, within the range. */
618 ASSERT_TRUE (example_a
.contains_point (2, 23));
620 /* On the line, at the end. */
621 ASSERT_TRUE (example_a
.contains_point (2, 38));
623 /* On the line, after the end. */
624 ASSERT_FALSE (example_a
.contains_point (2, 39));
626 /* After the line. */
627 ASSERT_FALSE (example_a
.contains_point (2, 39));
629 /* Tests for layout_range::intersects_line_p. */
630 ASSERT_FALSE (example_a
.intersects_line_p (1));
631 ASSERT_TRUE (example_a
.intersects_line_p (2));
632 ASSERT_FALSE (example_a
.intersects_line_p (3));
635 /* Selftest for layout_range, where the layout_range
636 is the multi-line range shown as "Example B" above. */
639 test_layout_range_for_multiple_lines ()
641 layout_range example_b
= make_range (3, 14, 5, 8);
643 /* Tests for layout_range::contains_point. */
645 /* Before first line. */
646 ASSERT_FALSE (example_b
.contains_point (1, 1));
648 /* On the first line, but before start. */
649 ASSERT_FALSE (example_b
.contains_point (3, 13));
652 ASSERT_TRUE (example_b
.contains_point (3, 14));
654 /* On the first line, within the range. */
655 ASSERT_TRUE (example_b
.contains_point (3, 15));
657 /* On an interior line.
658 The column number should not matter; try various boundary
660 ASSERT_TRUE (example_b
.contains_point (4, 1));
661 ASSERT_TRUE (example_b
.contains_point (4, 7));
662 ASSERT_TRUE (example_b
.contains_point (4, 8));
663 ASSERT_TRUE (example_b
.contains_point (4, 9));
664 ASSERT_TRUE (example_b
.contains_point (4, 13));
665 ASSERT_TRUE (example_b
.contains_point (4, 14));
666 ASSERT_TRUE (example_b
.contains_point (4, 15));
668 /* On the final line, before the end. */
669 ASSERT_TRUE (example_b
.contains_point (5, 7));
671 /* On the final line, at the end. */
672 ASSERT_TRUE (example_b
.contains_point (5, 8));
674 /* On the final line, after the end. */
675 ASSERT_FALSE (example_b
.contains_point (5, 9));
677 /* After the line. */
678 ASSERT_FALSE (example_b
.contains_point (6, 1));
680 /* Tests for layout_range::intersects_line_p. */
681 ASSERT_FALSE (example_b
.intersects_line_p (2));
682 ASSERT_TRUE (example_b
.intersects_line_p (3));
683 ASSERT_TRUE (example_b
.intersects_line_p (4));
684 ASSERT_TRUE (example_b
.intersects_line_p (5));
685 ASSERT_FALSE (example_b
.intersects_line_p (6));
688 #endif /* #if CHECKING_P */
690 /* Given a source line LINE of length LINE_WIDTH, determine the width
691 without any trailing whitespace. */
694 get_line_width_without_trailing_whitespace (const char *line
, int line_width
)
696 int result
= line_width
;
699 char ch
= line
[result
- 1];
700 if (ch
== ' ' || ch
== '\t' || ch
== '\r')
705 gcc_assert (result
>= 0);
706 gcc_assert (result
<= line_width
);
707 gcc_assert (result
== 0 ||
708 (line
[result
- 1] != ' '
709 && line
[result
-1] != '\t'
710 && line
[result
-1] != '\r'));
716 /* A helper function for testing get_line_width_without_trailing_whitespace. */
719 assert_eq (const char *line
, int expected_width
)
722 = get_line_width_without_trailing_whitespace (line
, strlen (line
));
723 ASSERT_EQ (actual_value
, expected_width
);
726 /* Verify that get_line_width_without_trailing_whitespace is sane for
727 various inputs. It is not required to handle newlines. */
730 test_get_line_width_without_trailing_whitespace ()
736 assert_eq ("hello world", 11);
737 assert_eq ("hello world ", 11);
738 assert_eq ("hello world \t\t ", 11);
739 assert_eq ("hello world\r", 11);
742 #endif /* #if CHECKING_P */
744 /* Helper function for layout's ctor, for sanitizing locations relative
745 to the primary location within a diagnostic.
747 Compare LOC_A and LOC_B to see if it makes sense to print underlines
748 connecting their expanded locations. Doing so is only guaranteed to
749 make sense if the locations share the same macro expansion "history"
750 i.e. they can be traced through the same macro expansions, eventually
751 reaching an ordinary map.
753 This may be too strong a condition, but it effectively sanitizes
754 PR c++/70105, which has an example of printing an expression where the
755 final location of the expression is in a different macro, which
756 erroneously was leading to hundreds of lines of irrelevant source
760 compatible_locations_p (location_t loc_a
, location_t loc_b
)
762 if (IS_ADHOC_LOC (loc_a
))
763 loc_a
= get_location_from_adhoc_loc (line_table
, loc_a
);
764 if (IS_ADHOC_LOC (loc_b
))
765 loc_b
= get_location_from_adhoc_loc (line_table
, loc_b
);
767 /* If either location is one of the special locations outside of a
768 linemap, they are only compatible if they are equal. */
769 if (loc_a
< RESERVED_LOCATION_COUNT
770 || loc_b
< RESERVED_LOCATION_COUNT
)
771 return loc_a
== loc_b
;
773 const line_map
*map_a
= linemap_lookup (line_table
, loc_a
);
774 linemap_assert (map_a
);
776 const line_map
*map_b
= linemap_lookup (line_table
, loc_b
);
777 linemap_assert (map_b
);
779 /* Are they within the same map? */
782 /* Are both within the same macro expansion? */
783 if (linemap_macro_expansion_map_p (map_a
))
785 /* Expand each location towards the spelling location, and
787 const line_map_macro
*macro_map
= linemap_check_macro (map_a
);
788 location_t loc_a_toward_spelling
789 = linemap_macro_map_loc_unwind_toward_spelling (line_table
,
792 location_t loc_b_toward_spelling
793 = linemap_macro_map_loc_unwind_toward_spelling (line_table
,
796 return compatible_locations_p (loc_a_toward_spelling
,
797 loc_b_toward_spelling
);
800 /* Otherwise they are within the same ordinary map. */
805 /* Within different maps. */
807 /* If either is within a macro expansion, they are incompatible. */
808 if (linemap_macro_expansion_map_p (map_a
)
809 || linemap_macro_expansion_map_p (map_b
))
812 /* Within two different ordinary maps; they are compatible iff they
813 are in the same file. */
814 const line_map_ordinary
*ord_map_a
= linemap_check_ordinary (map_a
);
815 const line_map_ordinary
*ord_map_b
= linemap_check_ordinary (map_b
);
816 return ord_map_a
->to_file
== ord_map_b
->to_file
;
820 /* Comparator for sorting fix-it hints. */
823 fixit_cmp (const void *p_a
, const void *p_b
)
825 const fixit_hint
* hint_a
= *static_cast<const fixit_hint
* const *> (p_a
);
826 const fixit_hint
* hint_b
= *static_cast<const fixit_hint
* const *> (p_b
);
827 return hint_a
->get_start_loc () - hint_b
->get_start_loc ();
830 /* Implementation of class layout. */
832 /* Constructor for class layout.
834 Filter the ranges from the rich_location to those that we can
835 sanely print, populating m_layout_ranges and m_fixit_hints.
836 Determine the range of lines that we will print, splitting them
837 up into an ordered list of disjoint spans of contiguous line numbers.
838 Determine m_x_offset, to ensure that the primary caret
839 will fit within the max_width provided by the diagnostic_context. */
841 layout::layout (diagnostic_context
* context
,
842 rich_location
*richloc
,
843 diagnostic_t diagnostic_kind
)
844 : m_context (context
),
845 m_pp (context
->printer
),
846 m_primary_loc (richloc
->get_range (0)->m_loc
),
847 m_exploc (richloc
->get_expanded_location (0)),
848 m_colorizer (context
, diagnostic_kind
),
849 m_colorize_source_p (context
->colorize_source_p
),
850 m_show_labels_p (context
->show_labels_p
),
851 m_show_line_numbers_p (context
->show_line_numbers_p
),
852 m_layout_ranges (richloc
->get_num_locations ()),
853 m_fixit_hints (richloc
->get_num_fixit_hints ()),
854 m_line_spans (1 + richloc
->get_num_locations ()),
858 for (unsigned int idx
= 0; idx
< richloc
->get_num_locations (); idx
++)
860 /* This diagnostic printer can only cope with "sufficiently sane" ranges.
861 Ignore any ranges that are awkward to handle. */
862 const location_range
*loc_range
= richloc
->get_range (idx
);
863 maybe_add_location_range (loc_range
, idx
, false);
866 /* Populate m_fixit_hints, filtering to only those that are in the
868 for (unsigned int i
= 0; i
< richloc
->get_num_fixit_hints (); i
++)
870 const fixit_hint
*hint
= richloc
->get_fixit_hint (i
);
871 if (validate_fixit_hint_p (hint
))
872 m_fixit_hints
.safe_push (hint
);
875 /* Sort m_fixit_hints. */
876 m_fixit_hints
.qsort (fixit_cmp
);
878 /* Populate m_line_spans. */
879 calculate_line_spans ();
881 /* Determine m_linenum_width. */
882 gcc_assert (m_line_spans
.length () > 0);
883 const line_span
*last_span
= &m_line_spans
[m_line_spans
.length () - 1];
884 int highest_line
= last_span
->m_last_line
;
885 if (highest_line
< 0)
887 m_linenum_width
= num_digits (highest_line
);
888 /* If we're showing jumps in the line-numbering, allow at least 3 chars. */
889 if (m_line_spans
.length () > 1)
890 m_linenum_width
= MAX (m_linenum_width
, 3);
891 /* If there's a minimum margin width, apply it (subtracting 1 for the space
892 after the line number. */
893 m_linenum_width
= MAX (m_linenum_width
, context
->min_margin_width
- 1);
895 /* Adjust m_x_offset.
896 Center the primary caret to fit in max_width; all columns
897 will be adjusted accordingly. */
898 size_t max_width
= m_context
->caret_max_width
;
899 char_span line
= location_get_source_line (m_exploc
.file
, m_exploc
.line
);
900 if (line
&& (size_t)m_exploc
.column
<= line
.length ())
902 size_t right_margin
= CARET_LINE_MARGIN
;
903 size_t column
= m_exploc
.column
;
904 if (m_show_line_numbers_p
)
905 column
+= m_linenum_width
+ 2;
906 right_margin
= MIN (line
.length () - column
, right_margin
);
907 right_margin
= max_width
- right_margin
;
908 if (line
.length () >= max_width
&& column
> right_margin
)
909 m_x_offset
= column
- right_margin
;
910 gcc_assert (m_x_offset
>= 0);
913 if (context
->show_ruler_p
)
914 show_ruler (m_x_offset
+ max_width
);
917 /* Attempt to add LOC_RANGE to m_layout_ranges, filtering them to
918 those that we can sanely print.
920 ORIGINAL_IDX is the index of LOC_RANGE within its rich_location,
921 (for use as extrinsic state by label ranges FIXME).
923 If RESTRICT_TO_CURRENT_LINE_SPANS is true, then LOC_RANGE is also
924 filtered against this layout instance's current line spans: it
925 will only be added if the location is fully within the lines
926 already specified by other locations.
928 Return true iff LOC_RANGE was added. */
931 layout::maybe_add_location_range (const location_range
*loc_range
,
932 unsigned original_idx
,
933 bool restrict_to_current_line_spans
)
935 gcc_assert (loc_range
);
937 /* Split the "range" into caret and range information. */
938 source_range src_range
= get_range_from_loc (line_table
, loc_range
->m_loc
);
940 /* Expand the various locations. */
941 expanded_location start
942 = linemap_client_expand_location_to_spelling_point
943 (src_range
.m_start
, LOCATION_ASPECT_START
);
944 expanded_location finish
945 = linemap_client_expand_location_to_spelling_point
946 (src_range
.m_finish
, LOCATION_ASPECT_FINISH
);
947 expanded_location caret
948 = linemap_client_expand_location_to_spelling_point
949 (loc_range
->m_loc
, LOCATION_ASPECT_CARET
);
951 /* If any part of the range isn't in the same file as the primary
952 location of this diagnostic, ignore the range. */
953 if (start
.file
!= m_exploc
.file
)
955 if (finish
.file
!= m_exploc
.file
)
957 if (loc_range
->m_range_display_kind
== SHOW_RANGE_WITH_CARET
)
958 if (caret
.file
!= m_exploc
.file
)
961 /* Sanitize the caret location for non-primary ranges. */
962 if (m_layout_ranges
.length () > 0)
963 if (loc_range
->m_range_display_kind
== SHOW_RANGE_WITH_CARET
)
964 if (!compatible_locations_p (loc_range
->m_loc
, m_primary_loc
))
965 /* Discard any non-primary ranges that can't be printed
966 sanely relative to the primary location. */
969 /* Everything is now known to be in the correct source file,
970 but it may require further sanitization. */
971 layout_range
ri (&start
, &finish
, loc_range
->m_range_display_kind
, &caret
,
972 original_idx
, loc_range
->m_label
);
974 /* If we have a range that finishes before it starts (perhaps
975 from something built via macro expansion), printing the
976 range is likely to be nonsensical. Also, attempting to do so
977 breaks assumptions within the printing code (PR c/68473).
978 Similarly, don't attempt to print ranges if one or both ends
979 of the range aren't sane to print relative to the
980 primary location (PR c++/70105). */
981 if (start
.line
> finish
.line
982 || !compatible_locations_p (src_range
.m_start
, m_primary_loc
)
983 || !compatible_locations_p (src_range
.m_finish
, m_primary_loc
))
985 /* Is this the primary location? */
986 if (m_layout_ranges
.length () == 0)
988 /* We want to print the caret for the primary location, but
989 we must sanitize away m_start and m_finish. */
990 ri
.m_start
= ri
.m_caret
;
991 ri
.m_finish
= ri
.m_caret
;
994 /* This is a non-primary range; ignore it. */
998 /* Potentially filter to just the lines already specified by other
999 locations. This is for use by gcc_rich_location::add_location_if_nearby.
1000 The layout ctor doesn't use it, and can't because m_line_spans
1001 hasn't been set up at that point. */
1002 if (restrict_to_current_line_spans
)
1004 if (!will_show_line_p (start
.line
))
1006 if (!will_show_line_p (finish
.line
))
1008 if (loc_range
->m_range_display_kind
== SHOW_RANGE_WITH_CARET
)
1009 if (!will_show_line_p (caret
.line
))
1013 /* Passed all the tests; add the range to m_layout_ranges so that
1014 it will be printed. */
1015 m_layout_ranges
.safe_push (ri
);
1019 /* Return true iff ROW is within one of the line spans for this layout. */
1022 layout::will_show_line_p (linenum_type row
) const
1024 for (int line_span_idx
= 0; line_span_idx
< get_num_line_spans ();
1027 const line_span
*line_span
= get_line_span (line_span_idx
);
1028 if (line_span
->contains_line_p (row
))
1034 /* Print a line showing a gap in the line numbers, for showing the boundary
1035 between two line spans. */
1038 layout::print_gap_in_line_numbering ()
1040 gcc_assert (m_show_line_numbers_p
);
1042 for (int i
= 0; i
< m_linenum_width
+ 1; i
++)
1043 pp_character (m_pp
, '.');
1048 /* Return true iff we should print a heading when starting the
1049 line span with the given index. */
1052 layout::print_heading_for_line_span_index_p (int line_span_idx
) const
1054 /* We print a heading for every change of line span, hence for every
1055 line span after the initial one. */
1056 if (line_span_idx
> 0)
1059 /* We also do it for the initial span if the primary location of the
1060 diagnostic is in a different span. */
1061 if (m_exploc
.line
> (int)get_line_span (0)->m_last_line
)
1067 /* Get an expanded_location for the first location of interest within
1068 the given line_span.
1069 Used when printing a heading to indicate a new line span. */
1072 layout::get_expanded_location (const line_span
*line_span
) const
1074 /* Whenever possible, use the caret location. */
1075 if (line_span
->contains_line_p (m_exploc
.line
))
1078 /* Otherwise, use the start of the first range that's present
1079 within the line_span. */
1080 for (unsigned int i
= 0; i
< m_layout_ranges
.length (); i
++)
1082 const layout_range
*lr
= &m_layout_ranges
[i
];
1083 if (line_span
->contains_line_p (lr
->m_start
.m_line
))
1085 expanded_location exploc
= m_exploc
;
1086 exploc
.line
= lr
->m_start
.m_line
;
1087 exploc
.column
= lr
->m_start
.m_column
;
1092 /* Otherwise, use the location of the first fixit-hint present within
1094 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1096 const fixit_hint
*hint
= m_fixit_hints
[i
];
1097 location_t loc
= hint
->get_start_loc ();
1098 expanded_location exploc
= expand_location (loc
);
1099 if (line_span
->contains_line_p (exploc
.line
))
1103 /* It should not be possible to have a line span that didn't
1104 contain any of the layout_range or fixit_hint instances. */
1109 /* Determine if HINT is meaningful to print within this layout. */
1112 layout::validate_fixit_hint_p (const fixit_hint
*hint
)
1114 if (LOCATION_FILE (hint
->get_start_loc ()) != m_exploc
.file
)
1116 if (LOCATION_FILE (hint
->get_next_loc ()) != m_exploc
.file
)
1122 /* Determine the range of lines affected by HINT.
1123 This assumes that HINT has already been filtered by
1124 validate_fixit_hint_p, and so affects the correct source file. */
1127 get_line_span_for_fixit_hint (const fixit_hint
*hint
)
1131 int start_line
= LOCATION_LINE (hint
->get_start_loc ());
1133 /* For line-insertion fix-it hints, add the previous line to the
1134 span, to give the user more context on the proposed change. */
1135 if (hint
->ends_with_newline_p ())
1139 return line_span (start_line
,
1140 LOCATION_LINE (hint
->get_next_loc ()));
1143 /* We want to print the pertinent source code at a diagnostic. The
1144 rich_location can contain multiple locations. This will have been
1145 filtered into m_exploc (the caret for the primary location) and
1146 m_layout_ranges, for those ranges within the same source file.
1148 We will print a subset of the lines within the source file in question,
1149 as a collection of "spans" of lines.
1151 This function populates m_line_spans with an ordered, disjoint list of
1152 the line spans of interest.
1154 Printing a gap between line spans takes one line, so, when printing
1155 line numbers, we allow a gap of up to one line between spans when
1156 merging, since it makes more sense to print the source line rather than a
1157 "gap-in-line-numbering" line. When not printing line numbers, it's
1158 better to be more explicit about what's going on, so keeping them as
1159 separate spans is preferred.
1161 For example, if the primary range is on lines 8-10, with secondary ranges
1162 covering lines 5-6 and lines 13-15:
1178 With line numbering on, we want two spans: lines 5-10 and lines 13-15.
1180 With line numbering off (with span headers), we want three spans: lines 5-6,
1181 lines 8-10, and lines 13-15. */
1184 layout::calculate_line_spans ()
1186 /* This should only be called once, by the ctor. */
1187 gcc_assert (m_line_spans
.length () == 0);
1189 /* Populate tmp_spans with individual spans, for each of
1190 m_exploc, and for m_layout_ranges. */
1191 auto_vec
<line_span
> tmp_spans (1 + m_layout_ranges
.length ());
1192 tmp_spans
.safe_push (line_span (m_exploc
.line
, m_exploc
.line
));
1193 for (unsigned int i
= 0; i
< m_layout_ranges
.length (); i
++)
1195 const layout_range
*lr
= &m_layout_ranges
[i
];
1196 gcc_assert (lr
->m_start
.m_line
<= lr
->m_finish
.m_line
);
1197 tmp_spans
.safe_push (line_span (lr
->m_start
.m_line
,
1198 lr
->m_finish
.m_line
));
1201 /* Also add spans for any fix-it hints, in case they cover other lines. */
1202 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1204 const fixit_hint
*hint
= m_fixit_hints
[i
];
1206 tmp_spans
.safe_push (get_line_span_for_fixit_hint (hint
));
1210 tmp_spans
.qsort(line_span::comparator
);
1212 /* Now iterate through tmp_spans, copying into m_line_spans, and
1213 combining where possible. */
1214 gcc_assert (tmp_spans
.length () > 0);
1215 m_line_spans
.safe_push (tmp_spans
[0]);
1216 for (unsigned int i
= 1; i
< tmp_spans
.length (); i
++)
1218 line_span
*current
= &m_line_spans
[m_line_spans
.length () - 1];
1219 const line_span
*next
= &tmp_spans
[i
];
1220 gcc_assert (next
->m_first_line
>= current
->m_first_line
);
1221 const int merger_distance
= m_show_line_numbers_p
? 1 : 0;
1222 if ((linenum_arith_t
)next
->m_first_line
1223 <= (linenum_arith_t
)current
->m_last_line
+ 1 + merger_distance
)
1225 /* We can merge them. */
1226 if (next
->m_last_line
> current
->m_last_line
)
1227 current
->m_last_line
= next
->m_last_line
;
1231 /* No merger possible. */
1232 m_line_spans
.safe_push (*next
);
1236 /* Verify the result, in m_line_spans. */
1237 gcc_assert (m_line_spans
.length () > 0);
1238 for (unsigned int i
= 1; i
< m_line_spans
.length (); i
++)
1240 const line_span
*prev
= &m_line_spans
[i
- 1];
1241 const line_span
*next
= &m_line_spans
[i
];
1242 /* The individual spans must be sane. */
1243 gcc_assert (prev
->m_first_line
<= prev
->m_last_line
);
1244 gcc_assert (next
->m_first_line
<= next
->m_last_line
);
1245 /* The spans must be ordered. */
1246 gcc_assert (prev
->m_first_line
< next
->m_first_line
);
1247 /* There must be a gap of at least one line between separate spans. */
1248 gcc_assert ((prev
->m_last_line
+ 1) < next
->m_first_line
);
1252 /* Print line ROW of source code, potentially colorized at any ranges, and
1253 populate *LBOUNDS_OUT.
1254 LINE is the source line (not necessarily 0-terminated) and LINE_WIDTH
1258 layout::print_source_line (linenum_type row
, const char *line
, int line_width
,
1259 line_bounds
*lbounds_out
)
1261 m_colorizer
.set_normal_text ();
1263 /* We will stop printing the source line at any trailing
1265 line_width
= get_line_width_without_trailing_whitespace (line
,
1269 if (m_show_line_numbers_p
)
1271 int width
= num_digits (row
);
1272 for (int i
= 0; i
< m_linenum_width
- width
; i
++)
1274 pp_printf (m_pp
, "%i | ", row
);
1278 int first_non_ws
= INT_MAX
;
1279 int last_non_ws
= 0;
1281 for (column
= 1 + m_x_offset
; column
<= line_width
; column
++)
1283 /* Assuming colorization is enabled for the caret and underline
1284 characters, we may also colorize the associated characters
1285 within the source line.
1287 For frontends that generate range information, we color the
1288 associated characters in the source line the same as the
1289 carets and underlines in the annotation line, to make it easier
1290 for the reader to see the pertinent code.
1292 For frontends that only generate carets, we don't colorize the
1293 characters above them, since this would look strange (e.g.
1294 colorizing just the first character in a token). */
1295 if (m_colorize_source_p
)
1299 in_range_p
= get_state_at_point (row
, column
,
1303 m_colorizer
.set_range (state
.range_idx
);
1305 m_colorizer
.set_normal_text ();
1308 if (c
== '\0' || c
== '\t' || c
== '\r')
1312 last_non_ws
= column
;
1313 if (first_non_ws
== INT_MAX
)
1314 first_non_ws
= column
;
1316 pp_character (m_pp
, c
);
1321 lbounds_out
->m_first_non_ws
= first_non_ws
;
1322 lbounds_out
->m_last_non_ws
= last_non_ws
;
1325 /* Determine if we should print an annotation line for ROW.
1326 i.e. if any of m_layout_ranges contains ROW. */
1329 layout::should_print_annotation_line_p (linenum_type row
) const
1331 layout_range
*range
;
1333 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1335 if (range
->m_range_display_kind
== SHOW_LINES_WITHOUT_RANGE
)
1337 if (range
->intersects_line_p (row
))
1343 /* Begin an annotation line. If m_show_line_numbers_p, print the left
1344 margin, which is empty for annotation lines. Otherwise, do nothing. */
1347 layout::start_annotation_line (char margin_char
) const
1349 if (m_show_line_numbers_p
)
1351 /* Print the margin. If MARGIN_CHAR != ' ', then print up to 3
1352 of it, right-aligned, padded with spaces. */
1354 for (i
= 0; i
< m_linenum_width
- 3; i
++)
1356 for (; i
< m_linenum_width
; i
++)
1357 pp_character (m_pp
, margin_char
);
1358 pp_string (m_pp
, " |");
1362 /* Print a line consisting of the caret/underlines for the given
1366 layout::print_annotation_line (linenum_type row
, const line_bounds lbounds
)
1368 int x_bound
= get_x_bound_for_row (row
, m_exploc
.column
,
1369 lbounds
.m_last_non_ws
);
1371 start_annotation_line ();
1374 for (int column
= 1 + m_x_offset
; column
< x_bound
; column
++)
1378 in_range_p
= get_state_at_point (row
, column
,
1379 lbounds
.m_first_non_ws
,
1380 lbounds
.m_last_non_ws
,
1384 /* Within a range. Draw either the caret or an underline. */
1385 m_colorizer
.set_range (state
.range_idx
);
1386 if (state
.draw_caret_p
)
1388 /* Draw the caret. */
1390 if (state
.range_idx
< rich_location::STATICALLY_ALLOCATED_RANGES
)
1391 caret_char
= m_context
->caret_chars
[state
.range_idx
];
1394 pp_character (m_pp
, caret_char
);
1397 pp_character (m_pp
, '~');
1401 /* Not in a range. */
1402 m_colorizer
.set_normal_text ();
1403 pp_character (m_pp
, ' ');
1409 /* Implementation detail of layout::print_any_labels.
1411 A label within the given row of source. */
1416 line_label (int state_idx
, int column
, label_text text
)
1417 : m_state_idx (state_idx
), m_column (column
),
1418 m_text (text
), m_length (strlen (text
.m_buffer
)),
1422 /* Sorting is primarily by column, then by state index. */
1423 static int comparator (const void *p1
, const void *p2
)
1425 const line_label
*ll1
= (const line_label
*)p1
;
1426 const line_label
*ll2
= (const line_label
*)p2
;
1427 int column_cmp
= compare (ll1
->m_column
, ll2
->m_column
);
1430 return compare (ll1
->m_state_idx
, ll2
->m_state_idx
);
1440 /* Print any labels in this row. */
1442 layout::print_any_labels (linenum_type row
)
1445 auto_vec
<line_label
> labels
;
1447 /* Gather the labels that are to be printed into "labels". */
1449 layout_range
*range
;
1450 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1452 /* Most ranges don't have labels, so reject this first. */
1453 if (range
->m_label
== NULL
)
1456 /* The range's caret must be on this line. */
1457 if (range
->m_caret
.m_line
!= row
)
1460 /* Reject labels that aren't fully visible due to clipping
1462 if (range
->m_caret
.m_column
<= m_x_offset
)
1466 text
= range
->m_label
->get_text (range
->m_original_idx
);
1468 /* Allow for labels that return NULL from their get_text
1469 implementation (so e.g. such labels can control their own
1471 if (text
.m_buffer
== NULL
)
1474 labels
.safe_push (line_label (i
, range
->m_caret
.m_column
, text
));
1478 /* Bail out if there are no labels on this row. */
1479 if (labels
.length () == 0)
1483 labels
.qsort(line_label::comparator
);
1485 /* Figure out how many "label lines" we need, and which
1486 one each label is printed in.
1488 For example, if the labels aren't too densely packed,
1489 we can fit them on the same line, giving two "label lines":
1494 l0 l1 : label line 1
1496 If they would touch each other or overlap, then we need
1497 additional "label lines":
1502 | label 1 : label line 1
1503 label 0 : label line 2
1505 Place the final label on label line 1, and work backwards, adding
1506 label lines as needed.
1508 If multiple labels are at the same place, put them on separate
1514 label 1 : label line 2
1515 label 0 : label line 3. */
1517 int max_label_line
= 1;
1519 int next_column
= INT_MAX
;
1521 FOR_EACH_VEC_ELT_REVERSE (labels
, i
, label
)
1523 /* Would this label "touch" or overlap the next label? */
1524 if (label
->m_column
+ label
->m_length
>= (size_t)next_column
)
1527 label
->m_label_line
= max_label_line
;
1528 next_column
= label
->m_column
;
1532 /* Print the "label lines". For each label within the line, print
1533 either a vertical bar ('|') for the labels that are lower down, or the
1534 labels themselves once we've reached their line. */
1536 /* Keep track of in which column we last printed a vertical bar.
1537 This allows us to suppress duplicate vertical bars for the case
1538 where multiple labels are on one column. */
1540 for (int label_line
= 0; label_line
<= max_label_line
; label_line
++)
1542 start_annotation_line ();
1544 int column
= 1 + m_x_offset
;
1546 FOR_EACH_VEC_ELT (labels
, i
, label
)
1548 if (label_line
> label
->m_label_line
)
1549 /* We've printed all the labels for this label line. */
1552 if (label_line
== label
->m_label_line
)
1554 gcc_assert (column
<= label
->m_column
);
1555 move_to_column (&column
, label
->m_column
, true);
1556 m_colorizer
.set_range (label
->m_state_idx
);
1557 pp_string (m_pp
, label
->m_text
.m_buffer
);
1558 m_colorizer
.set_normal_text ();
1559 column
+= label
->m_length
;
1561 else if (label
->m_column
!= last_vbar
)
1563 gcc_assert (column
<= label
->m_column
);
1564 move_to_column (&column
, label
->m_column
, true);
1565 m_colorizer
.set_range (label
->m_state_idx
);
1566 pp_character (m_pp
, '|');
1567 m_colorizer
.set_normal_text ();
1579 FOR_EACH_VEC_ELT (labels
, i
, label
)
1580 label
->m_text
.maybe_free ();
1584 /* If there are any fixit hints inserting new lines before source line ROW,
1587 They are printed on lines of their own, before the source line
1588 itself, with a leading '+'. */
1591 layout::print_leading_fixits (linenum_type row
)
1593 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1595 const fixit_hint
*hint
= m_fixit_hints
[i
];
1597 if (!hint
->ends_with_newline_p ())
1598 /* Not a newline fixit; print it in print_trailing_fixits. */
1601 gcc_assert (hint
->insertion_p ());
1603 if (hint
->affects_line_p (m_exploc
.file
, row
))
1605 /* Printing the '+' with normal colorization
1606 and the inserted line with "insert" colorization
1607 helps them stand out from each other, and from
1608 the surrounding text. */
1609 m_colorizer
.set_normal_text ();
1610 start_annotation_line ('+');
1611 pp_character (m_pp
, '+');
1612 m_colorizer
.set_fixit_insert ();
1613 /* Print all but the trailing newline of the fix-it hint.
1614 We have to print the newline separately to avoid
1615 getting additional pp prefixes printed. */
1616 for (size_t i
= 0; i
< hint
->get_length () - 1; i
++)
1617 pp_character (m_pp
, hint
->get_string ()[i
]);
1618 m_colorizer
.set_normal_text ();
1624 /* Subroutine of layout::print_trailing_fixits.
1626 Determine if the annotation line printed for LINE contained
1627 the exact range from START_COLUMN to FINISH_COLUMN. */
1630 layout::annotation_line_showed_range_p (linenum_type line
, int start_column
,
1631 int finish_column
) const
1633 layout_range
*range
;
1635 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1636 if (range
->m_start
.m_line
== line
1637 && range
->m_start
.m_column
== start_column
1638 && range
->m_finish
.m_line
== line
1639 && range
->m_finish
.m_column
== finish_column
)
1644 /* Classes for printing trailing fix-it hints i.e. those that
1645 don't add new lines.
1647 For insertion, these can look like:
1651 For replacement, these can look like:
1653 ------------- : underline showing affected range
1656 For deletion, these can look like:
1658 ------------- : underline showing affected range
1660 This can become confusing if they overlap, and so we need
1661 to do some preprocessing to decide what to print.
1662 We use the list of fixit_hint instances affecting the line
1663 to build a list of "correction" instances, and print the
1666 For example, consider a set of fix-its for converting
1667 a C-style cast to a C++ const_cast.
1671 ..000000000111111111122222222223333333333.
1672 ..123456789012345678901234567890123456789.
1673 foo *f = (foo *)ptr->field;
1676 and the fix-it hints:
1677 - replace col 10 (the open paren) with "const_cast<"
1678 - replace col 16 (the close paren) with "> ("
1679 - insert ")" before col 27
1681 then we would get odd-looking output:
1683 foo *f = (foo *)ptr->field;
1690 It would be better to detect when fixit hints are going to
1691 overlap (those that require new lines), and to consolidate
1692 the printing of such fixits, giving something like:
1694 foo *f = (foo *)ptr->field;
1697 const_cast<foo *> (ptr->field)
1699 This works by detecting when the printing would overlap, and
1700 effectively injecting no-op replace hints into the gaps between
1701 such fix-its, so that the printing joins up.
1703 In the above example, the overlap of:
1704 - replace col 10 (the open paren) with "const_cast<"
1706 - replace col 16 (the close paren) with "> ("
1707 is fixed by injecting a no-op:
1708 - replace cols 11-15 with themselves ("foo *")
1709 and consolidating these, making:
1710 - replace cols 10-16 with "const_cast<" + "foo *" + "> ("
1712 - replace cols 10-16 with "const_cast<foo *> ("
1714 This overlaps with the final fix-it hint:
1715 - insert ")" before col 27
1716 and so we repeat the consolidation process, by injecting
1718 - replace cols 17-26 with themselves ("ptr->field")
1720 - replace cols 10-26 with "const_cast<foo *> (" + "ptr->field" + ")"
1722 - replace cols 10-26 with "const_cast<foo *> (ptr->field)"
1724 and is thus printed as desired. */
1726 /* A range of columns within a line. */
1731 column_range (int start_
, int finish_
) : start (start_
), finish (finish_
)
1733 /* We must have either a range, or an insertion. */
1734 gcc_assert (start
<= finish
|| finish
== start
- 1);
1737 bool operator== (const column_range
&other
) const
1739 return start
== other
.start
&& finish
== other
.finish
;
1746 /* Get the range of columns that HINT would affect. */
1749 get_affected_columns (const fixit_hint
*hint
)
1751 int start_column
= LOCATION_COLUMN (hint
->get_start_loc ());
1752 int finish_column
= LOCATION_COLUMN (hint
->get_next_loc ()) - 1;
1754 return column_range (start_column
, finish_column
);
1757 /* Get the range of columns that would be printed for HINT. */
1760 get_printed_columns (const fixit_hint
*hint
)
1762 int start_column
= LOCATION_COLUMN (hint
->get_start_loc ());
1763 int final_hint_column
= start_column
+ hint
->get_length () - 1;
1764 if (hint
->insertion_p ())
1766 return column_range (start_column
, final_hint_column
);
1770 int finish_column
= LOCATION_COLUMN (hint
->get_next_loc ()) - 1;
1772 return column_range (start_column
,
1773 MAX (finish_column
, final_hint_column
));
1777 /* A correction on a particular line.
1778 This describes a plan for how to print one or more fixit_hint
1779 instances that affected the line, potentially consolidating hints
1780 into corrections to make the result easier for the user to read. */
1785 correction (column_range affected_columns
,
1786 column_range printed_columns
,
1787 const char *new_text
, size_t new_text_len
)
1788 : m_affected_columns (affected_columns
),
1789 m_printed_columns (printed_columns
),
1790 m_text (xstrdup (new_text
)),
1791 m_len (new_text_len
),
1792 m_alloc_sz (new_text_len
+ 1)
1796 ~correction () { free (m_text
); }
1798 bool insertion_p () const
1800 return m_affected_columns
.start
== m_affected_columns
.finish
+ 1;
1803 void ensure_capacity (size_t len
);
1804 void ensure_terminated ();
1806 void overwrite (int dst_offset
, const char_span
&src_span
)
1808 gcc_assert (dst_offset
>= 0);
1809 gcc_assert (dst_offset
+ src_span
.length () < m_alloc_sz
);
1810 memcpy (m_text
+ dst_offset
, src_span
.get_buffer (),
1811 src_span
.length ());
1814 /* If insert, then start: the column before which the text
1815 is to be inserted, and finish is offset by the length of
1817 If replace, then the range of columns affected. */
1818 column_range m_affected_columns
;
1820 /* If insert, then start: the column before which the text
1821 is to be inserted, and finish is offset by the length of
1823 If replace, then the range of columns affected. */
1824 column_range m_printed_columns
;
1826 /* The text to be inserted/used as replacement. */
1832 /* Ensure that m_text can hold a string of length LEN
1833 (plus 1 for 0-termination). */
1836 correction::ensure_capacity (size_t len
)
1838 /* Allow 1 extra byte for 0-termination. */
1839 if (m_alloc_sz
< (len
+ 1))
1841 size_t new_alloc_sz
= (len
+ 1) * 2;
1842 m_text
= (char *)xrealloc (m_text
, new_alloc_sz
);
1843 m_alloc_sz
= new_alloc_sz
;
1847 /* Ensure that m_text is 0-terminated. */
1850 correction::ensure_terminated ()
1852 /* 0-terminate the buffer. */
1853 gcc_assert (m_len
< m_alloc_sz
);
1854 m_text
[m_len
] = '\0';
1857 /* A list of corrections affecting a particular line.
1858 This is used by layout::print_trailing_fixits for planning
1859 how to print the fix-it hints affecting the line. */
1861 class line_corrections
1864 line_corrections (const char *filename
, linenum_type row
)
1865 : m_filename (filename
), m_row (row
)
1867 ~line_corrections ();
1869 void add_hint (const fixit_hint
*hint
);
1871 const char *m_filename
;
1873 auto_vec
<correction
*> m_corrections
;
1876 /* struct line_corrections. */
1878 line_corrections::~line_corrections ()
1882 FOR_EACH_VEC_ELT (m_corrections
, i
, c
)
1886 /* A struct wrapping a particular source line, allowing
1887 run-time bounds-checking of accesses in a checked build. */
1892 source_line (const char *filename
, int line
);
1894 char_span
as_span () { return char_span (chars
, width
); }
1900 /* source_line's ctor. */
1902 source_line::source_line (const char *filename
, int line
)
1904 char_span span
= location_get_source_line (filename
, line
);
1905 chars
= span
.get_buffer ();
1906 width
= span
.length ();
1909 /* Add HINT to the corrections for this line.
1910 Attempt to consolidate nearby hints so that they will not
1911 overlap with printed. */
1914 line_corrections::add_hint (const fixit_hint
*hint
)
1916 column_range affected_columns
= get_affected_columns (hint
);
1917 column_range printed_columns
= get_printed_columns (hint
);
1919 /* Potentially consolidate. */
1920 if (!m_corrections
.is_empty ())
1922 correction
*last_correction
1923 = m_corrections
[m_corrections
.length () - 1];
1925 /* The following consolidation code assumes that the fix-it hints
1926 have been sorted by start (done within layout's ctor). */
1927 gcc_assert (affected_columns
.start
1928 >= last_correction
->m_affected_columns
.start
);
1929 gcc_assert (printed_columns
.start
1930 >= last_correction
->m_printed_columns
.start
);
1932 if (printed_columns
.start
<= last_correction
->m_printed_columns
.finish
)
1934 /* We have two hints for which the printed forms of the hints
1935 would touch or overlap, so we need to consolidate them to avoid
1937 Attempt to inject a "replace" correction from immediately
1938 after the end of the last hint to immediately before the start
1939 of the next hint. */
1940 column_range
between (last_correction
->m_affected_columns
.finish
+ 1,
1941 printed_columns
.start
- 1);
1943 /* Try to read the source. */
1944 source_line
line (m_filename
, m_row
);
1945 if (line
.chars
&& between
.finish
< line
.width
)
1947 /* Consolidate into the last correction:
1948 add a no-op "replace" of the "between" text, and
1949 add the text from the new hint. */
1950 int old_len
= last_correction
->m_len
;
1951 gcc_assert (old_len
>= 0);
1952 int between_len
= between
.finish
+ 1 - between
.start
;
1953 gcc_assert (between_len
>= 0);
1954 int new_len
= old_len
+ between_len
+ hint
->get_length ();
1955 gcc_assert (new_len
>= 0);
1956 last_correction
->ensure_capacity (new_len
);
1957 last_correction
->overwrite
1959 line
.as_span ().subspan (between
.start
- 1,
1960 between
.finish
+ 1 - between
.start
));
1961 last_correction
->overwrite (old_len
+ between_len
,
1962 char_span (hint
->get_string (),
1963 hint
->get_length ()));
1964 last_correction
->m_len
= new_len
;
1965 last_correction
->ensure_terminated ();
1966 last_correction
->m_affected_columns
.finish
1967 = affected_columns
.finish
;
1968 last_correction
->m_printed_columns
.finish
1969 += between_len
+ hint
->get_length ();
1975 /* If no consolidation happened, add a new correction instance. */
1976 m_corrections
.safe_push (new correction (affected_columns
,
1978 hint
->get_string (),
1979 hint
->get_length ()));
1982 /* If there are any fixit hints on source line ROW, print them.
1983 They are printed in order, attempting to combine them onto lines, but
1984 starting new lines if necessary.
1985 Fix-it hints that insert new lines are handled separately,
1986 in layout::print_leading_fixits. */
1989 layout::print_trailing_fixits (linenum_type row
)
1991 /* Build a list of correction instances for the line,
1992 potentially consolidating hints (for the sake of readability). */
1993 line_corrections
corrections (m_exploc
.file
, row
);
1994 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1996 const fixit_hint
*hint
= m_fixit_hints
[i
];
1998 /* Newline fixits are handled by layout::print_leading_fixits. */
1999 if (hint
->ends_with_newline_p ())
2002 if (hint
->affects_line_p (m_exploc
.file
, row
))
2003 corrections
.add_hint (hint
);
2006 /* Now print the corrections. */
2009 int column
= m_x_offset
;
2011 if (!corrections
.m_corrections
.is_empty ())
2012 start_annotation_line ();
2014 FOR_EACH_VEC_ELT (corrections
.m_corrections
, i
, c
)
2016 /* For now we assume each fixit hint can only touch one line. */
2017 if (c
->insertion_p ())
2019 /* This assumes the insertion just affects one line. */
2020 int start_column
= c
->m_printed_columns
.start
;
2021 move_to_column (&column
, start_column
, true);
2022 m_colorizer
.set_fixit_insert ();
2023 pp_string (m_pp
, c
->m_text
);
2024 m_colorizer
.set_normal_text ();
2029 /* If the range of the replacement wasn't printed in the
2030 annotation line, then print an extra underline to
2031 indicate exactly what is being replaced.
2032 Always show it for removals. */
2033 int start_column
= c
->m_affected_columns
.start
;
2034 int finish_column
= c
->m_affected_columns
.finish
;
2035 if (!annotation_line_showed_range_p (row
, start_column
,
2039 move_to_column (&column
, start_column
, true);
2040 m_colorizer
.set_fixit_delete ();
2041 for (; column
<= finish_column
; column
++)
2042 pp_character (m_pp
, '-');
2043 m_colorizer
.set_normal_text ();
2045 /* Print the replacement text. REPLACE also covers
2046 removals, so only do this extra work (potentially starting
2047 a new line) if we have actual replacement text. */
2050 move_to_column (&column
, start_column
, true);
2051 m_colorizer
.set_fixit_insert ();
2052 pp_string (m_pp
, c
->m_text
);
2053 m_colorizer
.set_normal_text ();
2059 /* Add a trailing newline, if necessary. */
2060 move_to_column (&column
, 0, false);
2063 /* Disable any colorization and emit a newline. */
2066 layout::print_newline ()
2068 m_colorizer
.set_normal_text ();
2072 /* Return true if (ROW/COLUMN) is within a range of the layout.
2073 If it returns true, OUT_STATE is written to, with the
2074 range index, and whether we should draw the caret at
2075 (ROW/COLUMN) (as opposed to an underline). */
2078 layout::get_state_at_point (/* Inputs. */
2079 linenum_type row
, int column
,
2080 int first_non_ws
, int last_non_ws
,
2082 point_state
*out_state
)
2084 layout_range
*range
;
2086 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
2088 if (range
->m_range_display_kind
== SHOW_LINES_WITHOUT_RANGE
)
2089 /* Bail out early, so that such ranges don't affect underlining or
2090 source colorization. */
2093 if (range
->contains_point (row
, column
))
2095 out_state
->range_idx
= i
;
2097 /* Are we at the range's caret? is it visible? */
2098 out_state
->draw_caret_p
= false;
2099 if (range
->m_range_display_kind
== SHOW_RANGE_WITH_CARET
2100 && row
== range
->m_caret
.m_line
2101 && column
== range
->m_caret
.m_column
)
2102 out_state
->draw_caret_p
= true;
2104 /* Within a multiline range, don't display any underline
2105 in any leading or trailing whitespace on a line.
2106 We do display carets, however. */
2107 if (!out_state
->draw_caret_p
)
2108 if (column
< first_non_ws
|| column
> last_non_ws
)
2111 /* We are within a range. */
2119 /* Helper function for use by layout::print_line when printing the
2120 annotation line under the source line.
2121 Get the column beyond the rightmost one that could contain a caret or
2122 range marker, given that we stop rendering at trailing whitespace.
2123 ROW is the source line within the given file.
2124 CARET_COLUMN is the column of range 0's caret.
2125 LAST_NON_WS_COLUMN is the last column containing a non-whitespace
2126 character of source (as determined when printing the source line). */
2129 layout::get_x_bound_for_row (linenum_type row
, int caret_column
,
2130 int last_non_ws_column
)
2132 int result
= caret_column
+ 1;
2134 layout_range
*range
;
2136 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
2138 if (row
>= range
->m_start
.m_line
)
2140 if (range
->m_finish
.m_line
== row
)
2142 /* On the final line within a range; ensure that
2143 we render up to the end of the range. */
2144 if (result
<= range
->m_finish
.m_column
)
2145 result
= range
->m_finish
.m_column
+ 1;
2147 else if (row
< range
->m_finish
.m_line
)
2149 /* Within a multiline range; ensure that we render up to the
2150 last non-whitespace column. */
2151 if (result
<= last_non_ws_column
)
2152 result
= last_non_ws_column
+ 1;
2160 /* Given *COLUMN as an x-coordinate, print spaces to position
2161 successive output at DEST_COLUMN, printing a newline if necessary,
2162 and updating *COLUMN. If ADD_LEFT_MARGIN, then print the (empty)
2163 left margin after any newline. */
2166 layout::move_to_column (int *column
, int dest_column
, bool add_left_margin
)
2168 /* Start a new line if we need to. */
2169 if (*column
> dest_column
)
2172 if (add_left_margin
)
2173 start_annotation_line ();
2174 *column
= m_x_offset
;
2177 while (*column
< dest_column
)
2184 /* For debugging layout issues, render a ruler giving column numbers
2185 (after the 1-column indent). */
2188 layout::show_ruler (int max_column
) const
2191 if (max_column
> 99)
2193 start_annotation_line ();
2195 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
2196 if (column
% 10 == 0)
2197 pp_character (m_pp
, '0' + (column
/ 100) % 10);
2204 start_annotation_line ();
2206 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
2207 if (column
% 10 == 0)
2208 pp_character (m_pp
, '0' + (column
/ 10) % 10);
2214 start_annotation_line ();
2216 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
2217 pp_character (m_pp
, '0' + (column
% 10));
2221 /* Print leading fix-its (for new lines inserted before the source line)
2222 then the source line, followed by an annotation line
2223 consisting of any caret/underlines, then any fixits.
2224 If the source line can't be read, print nothing. */
2226 layout::print_line (linenum_type row
)
2228 char_span line
= location_get_source_line (m_exploc
.file
, row
);
2232 line_bounds lbounds
;
2233 print_leading_fixits (row
);
2234 print_source_line (row
, line
.get_buffer (), line
.length (), &lbounds
);
2235 if (should_print_annotation_line_p (row
))
2236 print_annotation_line (row
, lbounds
);
2237 if (m_show_labels_p
)
2238 print_any_labels (row
);
2239 print_trailing_fixits (row
);
2242 } /* End of anonymous namespace. */
2244 /* If LOC is within the spans of lines that will already be printed for
2245 this gcc_rich_location, then add it as a secondary location and return true.
2247 Otherwise return false. */
2250 gcc_rich_location::add_location_if_nearby (location_t loc
)
2252 /* Use the layout location-handling logic to sanitize LOC,
2253 filtering it to the current line spans within a temporary
2255 layout
layout (global_dc
, this, DK_ERROR
);
2256 location_range loc_range
;
2257 loc_range
.m_loc
= loc
;
2258 loc_range
.m_range_display_kind
= SHOW_RANGE_WITHOUT_CARET
;
2259 if (!layout
.maybe_add_location_range (&loc_range
, 0, true))
2266 /* Print the physical source code corresponding to the location of
2267 this diagnostic, with additional annotations. */
2270 diagnostic_show_locus (diagnostic_context
* context
,
2271 rich_location
*richloc
,
2272 diagnostic_t diagnostic_kind
)
2274 pp_newline (context
->printer
);
2276 location_t loc
= richloc
->get_loc ();
2277 /* Do nothing if source-printing has been disabled. */
2278 if (!context
->show_caret
)
2281 /* Don't attempt to print source for UNKNOWN_LOCATION and for builtins. */
2282 if (loc
<= BUILTINS_LOCATION
)
2285 /* Don't print the same source location twice in a row, unless we have
2287 if (loc
== context
->last_location
2288 && richloc
->get_num_fixit_hints () == 0)
2291 context
->last_location
= loc
;
2293 char *saved_prefix
= pp_take_prefix (context
->printer
);
2294 pp_set_prefix (context
->printer
, NULL
);
2296 layout
layout (context
, richloc
, diagnostic_kind
);
2297 for (int line_span_idx
= 0; line_span_idx
< layout
.get_num_line_spans ();
2300 const line_span
*line_span
= layout
.get_line_span (line_span_idx
);
2301 if (context
->show_line_numbers_p
)
2303 /* With line numbers, we should show whenever the line-numbering
2305 if (line_span_idx
> 0)
2306 layout
.print_gap_in_line_numbering ();
2310 /* Without line numbers, we print headings for some line spans. */
2311 if (layout
.print_heading_for_line_span_index_p (line_span_idx
))
2313 expanded_location exploc
2314 = layout
.get_expanded_location (line_span
);
2315 context
->start_span (context
, exploc
);
2318 /* Iterate over the lines within this span (using linenum_arith_t to
2319 avoid overflow with 0xffffffff causing an infinite loop). */
2320 linenum_arith_t last_line
= line_span
->get_last_line ();
2321 for (linenum_arith_t row
= line_span
->get_first_line ();
2322 row
<= last_line
; row
++)
2323 layout
.print_line (row
);
2326 pp_set_prefix (context
->printer
, saved_prefix
);
2331 namespace selftest
{
2333 /* Selftests for diagnostic_show_locus. */
2335 /* Verify that diagnostic_show_locus works sanely on UNKNOWN_LOCATION. */
2338 test_diagnostic_show_locus_unknown_location ()
2340 test_diagnostic_context dc
;
2341 rich_location
richloc (line_table
, UNKNOWN_LOCATION
);
2342 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2343 ASSERT_STREQ ("\n", pp_formatted_text (dc
.printer
));
2346 /* Verify that diagnostic_show_locus works sanely for various
2349 All of these work on the following 1-line source file:
2352 "foo = bar.field;\n"
2353 which is set up by test_diagnostic_show_locus_one_liner and calls
2359 test_one_liner_simple_caret ()
2361 test_diagnostic_context dc
;
2362 location_t caret
= linemap_position_for_column (line_table
, 10);
2363 rich_location
richloc (line_table
, caret
);
2364 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2366 " foo = bar.field;\n"
2368 pp_formatted_text (dc
.printer
));
2371 /* Caret and range. */
2374 test_one_liner_caret_and_range ()
2376 test_diagnostic_context dc
;
2377 location_t caret
= linemap_position_for_column (line_table
, 10);
2378 location_t start
= linemap_position_for_column (line_table
, 7);
2379 location_t finish
= linemap_position_for_column (line_table
, 15);
2380 location_t loc
= make_location (caret
, start
, finish
);
2381 rich_location
richloc (line_table
, loc
);
2382 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2384 " foo = bar.field;\n"
2386 pp_formatted_text (dc
.printer
));
2389 /* Multiple ranges and carets. */
2392 test_one_liner_multiple_carets_and_ranges ()
2394 test_diagnostic_context dc
;
2396 = make_location (linemap_position_for_column (line_table
, 2),
2397 linemap_position_for_column (line_table
, 1),
2398 linemap_position_for_column (line_table
, 3));
2399 dc
.caret_chars
[0] = 'A';
2402 = make_location (linemap_position_for_column (line_table
, 8),
2403 linemap_position_for_column (line_table
, 7),
2404 linemap_position_for_column (line_table
, 9));
2405 dc
.caret_chars
[1] = 'B';
2408 = make_location (linemap_position_for_column (line_table
, 13),
2409 linemap_position_for_column (line_table
, 11),
2410 linemap_position_for_column (line_table
, 15));
2411 dc
.caret_chars
[2] = 'C';
2413 rich_location
richloc (line_table
, foo
);
2414 richloc
.add_range (bar
, SHOW_RANGE_WITH_CARET
);
2415 richloc
.add_range (field
, SHOW_RANGE_WITH_CARET
);
2416 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2418 " foo = bar.field;\n"
2420 pp_formatted_text (dc
.printer
));
2423 /* Insertion fix-it hint: adding an "&" to the front of "bar.field". */
2426 test_one_liner_fixit_insert_before ()
2428 test_diagnostic_context dc
;
2429 location_t caret
= linemap_position_for_column (line_table
, 7);
2430 rich_location
richloc (line_table
, caret
);
2431 richloc
.add_fixit_insert_before ("&");
2432 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2434 " foo = bar.field;\n"
2437 pp_formatted_text (dc
.printer
));
2440 /* Insertion fix-it hint: adding a "[0]" after "foo". */
2443 test_one_liner_fixit_insert_after ()
2445 test_diagnostic_context dc
;
2446 location_t start
= linemap_position_for_column (line_table
, 1);
2447 location_t finish
= linemap_position_for_column (line_table
, 3);
2448 location_t foo
= make_location (start
, start
, finish
);
2449 rich_location
richloc (line_table
, foo
);
2450 richloc
.add_fixit_insert_after ("[0]");
2451 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2453 " foo = bar.field;\n"
2456 pp_formatted_text (dc
.printer
));
2459 /* Removal fix-it hint: removal of the ".field". */
2462 test_one_liner_fixit_remove ()
2464 test_diagnostic_context dc
;
2465 location_t start
= linemap_position_for_column (line_table
, 10);
2466 location_t finish
= linemap_position_for_column (line_table
, 15);
2467 location_t dot
= make_location (start
, start
, finish
);
2468 rich_location
richloc (line_table
, dot
);
2469 richloc
.add_fixit_remove ();
2470 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2472 " foo = bar.field;\n"
2475 pp_formatted_text (dc
.printer
));
2478 /* Replace fix-it hint: replacing "field" with "m_field". */
2481 test_one_liner_fixit_replace ()
2483 test_diagnostic_context dc
;
2484 location_t start
= linemap_position_for_column (line_table
, 11);
2485 location_t finish
= linemap_position_for_column (line_table
, 15);
2486 location_t field
= make_location (start
, start
, finish
);
2487 rich_location
richloc (line_table
, field
);
2488 richloc
.add_fixit_replace ("m_field");
2489 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2491 " foo = bar.field;\n"
2494 pp_formatted_text (dc
.printer
));
2497 /* Replace fix-it hint: replacing "field" with "m_field",
2498 but where the caret was elsewhere. */
2501 test_one_liner_fixit_replace_non_equal_range ()
2503 test_diagnostic_context dc
;
2504 location_t equals
= linemap_position_for_column (line_table
, 5);
2505 location_t start
= linemap_position_for_column (line_table
, 11);
2506 location_t finish
= linemap_position_for_column (line_table
, 15);
2507 rich_location
richloc (line_table
, equals
);
2509 range
.m_start
= start
;
2510 range
.m_finish
= finish
;
2511 richloc
.add_fixit_replace (range
, "m_field");
2512 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2513 /* The replacement range is not indicated in the annotation line, so
2514 it should be indicated via an additional underline. */
2516 " foo = bar.field;\n"
2520 pp_formatted_text (dc
.printer
));
2523 /* Replace fix-it hint: replacing "field" with "m_field",
2524 where the caret was elsewhere, but where a secondary range
2525 exactly covers "field". */
2528 test_one_liner_fixit_replace_equal_secondary_range ()
2530 test_diagnostic_context dc
;
2531 location_t equals
= linemap_position_for_column (line_table
, 5);
2532 location_t start
= linemap_position_for_column (line_table
, 11);
2533 location_t finish
= linemap_position_for_column (line_table
, 15);
2534 rich_location
richloc (line_table
, equals
);
2535 location_t field
= make_location (start
, start
, finish
);
2536 richloc
.add_range (field
);
2537 richloc
.add_fixit_replace (field
, "m_field");
2538 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2539 /* The replacement range is indicated in the annotation line,
2540 so it shouldn't be indicated via an additional underline. */
2542 " foo = bar.field;\n"
2545 pp_formatted_text (dc
.printer
));
2548 /* Verify that we can use ad-hoc locations when adding fixits to a
2552 test_one_liner_fixit_validation_adhoc_locations ()
2554 /* Generate a range that's too long to be packed, so must
2555 be stored as an ad-hoc location (given the defaults
2556 of 5 bits or 0 bits of packed range); 41 columns > 2**5. */
2557 const location_t c7
= linemap_position_for_column (line_table
, 7);
2558 const location_t c47
= linemap_position_for_column (line_table
, 47);
2559 const location_t loc
= make_location (c7
, c7
, c47
);
2561 if (c47
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2564 ASSERT_TRUE (IS_ADHOC_LOC (loc
));
2568 rich_location
richloc (line_table
, loc
);
2569 richloc
.add_fixit_insert_before (loc
, "test");
2570 /* It should not have been discarded by the validator. */
2571 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2573 test_diagnostic_context dc
;
2574 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2576 " foo = bar.field;\n"
2579 pp_formatted_text (dc
.printer
));
2584 rich_location
richloc (line_table
, loc
);
2585 source_range range
= source_range::from_locations (loc
, c47
);
2586 richloc
.add_fixit_remove (range
);
2587 /* It should not have been discarded by the validator. */
2588 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2590 test_diagnostic_context dc
;
2591 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2593 " foo = bar.field;\n"
2595 " -----------------------------------------\n",
2596 pp_formatted_text (dc
.printer
));
2601 rich_location
richloc (line_table
, loc
);
2602 source_range range
= source_range::from_locations (loc
, c47
);
2603 richloc
.add_fixit_replace (range
, "test");
2604 /* It should not have been discarded by the validator. */
2605 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2607 test_diagnostic_context dc
;
2608 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2610 " foo = bar.field;\n"
2613 pp_formatted_text (dc
.printer
));
2617 /* Test of consolidating insertions at the same location. */
2620 test_one_liner_many_fixits_1 ()
2622 test_diagnostic_context dc
;
2623 location_t equals
= linemap_position_for_column (line_table
, 5);
2624 rich_location
richloc (line_table
, equals
);
2625 for (int i
= 0; i
< 19; i
++)
2626 richloc
.add_fixit_insert_before ("a");
2627 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2628 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2630 " foo = bar.field;\n"
2632 " aaaaaaaaaaaaaaaaaaa\n",
2633 pp_formatted_text (dc
.printer
));
2636 /* Ensure that we can add an arbitrary number of fix-it hints to a
2637 rich_location, even if they are not consolidated. */
2640 test_one_liner_many_fixits_2 ()
2642 test_diagnostic_context dc
;
2643 location_t equals
= linemap_position_for_column (line_table
, 5);
2644 rich_location
richloc (line_table
, equals
);
2645 for (int i
= 0; i
< 19; i
++)
2647 location_t loc
= linemap_position_for_column (line_table
, i
* 2);
2648 richloc
.add_fixit_insert_before (loc
, "a");
2650 ASSERT_EQ (19, richloc
.get_num_fixit_hints ());
2651 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2653 " foo = bar.field;\n"
2655 "a a a a a a a a a a a a a a a a a a a\n",
2656 pp_formatted_text (dc
.printer
));
2659 /* Test of labeling the ranges within a rich_location. */
2662 test_one_liner_labels ()
2665 = make_location (linemap_position_for_column (line_table
, 1),
2666 linemap_position_for_column (line_table
, 1),
2667 linemap_position_for_column (line_table
, 3));
2669 = make_location (linemap_position_for_column (line_table
, 7),
2670 linemap_position_for_column (line_table
, 7),
2671 linemap_position_for_column (line_table
, 9));
2673 = make_location (linemap_position_for_column (line_table
, 11),
2674 linemap_position_for_column (line_table
, 11),
2675 linemap_position_for_column (line_table
, 15));
2677 /* Example where all the labels fit on one line. */
2679 text_range_label
label0 ("0");
2680 text_range_label
label1 ("1");
2681 text_range_label
label2 ("2");
2682 gcc_rich_location
richloc (foo
, &label0
);
2683 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
2684 richloc
.add_range (field
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
2687 test_diagnostic_context dc
;
2688 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2690 " foo = bar.field;\n"
2694 pp_formatted_text (dc
.printer
));
2697 /* Verify that we can disable label-printing. */
2699 test_diagnostic_context dc
;
2700 dc
.show_labels_p
= false;
2701 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2703 " foo = bar.field;\n"
2705 pp_formatted_text (dc
.printer
));
2709 /* Example where the labels need extra lines. */
2711 text_range_label
label0 ("label 0");
2712 text_range_label
label1 ("label 1");
2713 text_range_label
label2 ("label 2");
2714 gcc_rich_location
richloc (foo
, &label0
);
2715 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
2716 richloc
.add_range (field
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
2718 test_diagnostic_context dc
;
2719 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2721 " foo = bar.field;\n"
2727 pp_formatted_text (dc
.printer
));
2730 /* Example of boundary conditions: label 0 and 1 have just enough clearance,
2731 but label 1 just touches label 2. */
2733 text_range_label
label0 ("aaaaa");
2734 text_range_label
label1 ("bbbb");
2735 text_range_label
label2 ("c");
2736 gcc_rich_location
richloc (foo
, &label0
);
2737 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
2738 richloc
.add_range (field
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
2740 test_diagnostic_context dc
;
2741 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2743 " foo = bar.field;\n"
2748 pp_formatted_text (dc
.printer
));
2751 /* Example of out-of-order ranges (thus requiring a sort). */
2753 text_range_label
label0 ("0");
2754 text_range_label
label1 ("1");
2755 text_range_label
label2 ("2");
2756 gcc_rich_location
richloc (field
, &label0
);
2757 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
2758 richloc
.add_range (foo
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
2760 test_diagnostic_context dc
;
2761 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2763 " foo = bar.field;\n"
2767 pp_formatted_text (dc
.printer
));
2770 /* Ensure we don't ICE if multiple ranges with labels are on
2773 text_range_label
label0 ("label 0");
2774 text_range_label
label1 ("label 1");
2775 text_range_label
label2 ("label 2");
2776 gcc_rich_location
richloc (bar
, &label0
);
2777 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
2778 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
2780 test_diagnostic_context dc
;
2781 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2783 " foo = bar.field;\n"
2789 pp_formatted_text (dc
.printer
));
2792 /* Verify that a NULL result from range_label::get_text is
2793 handled gracefully. */
2795 text_range_label
label (NULL
);
2796 gcc_rich_location
richloc (bar
, &label
);
2798 test_diagnostic_context dc
;
2799 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2801 " foo = bar.field;\n"
2803 pp_formatted_text (dc
.printer
));
2806 /* TODO: example of formatted printing (needs to be in
2807 gcc-rich-location.c due to Makefile.in issues). */
2810 /* Run the various one-liner tests. */
2813 test_diagnostic_show_locus_one_liner (const line_table_case
&case_
)
2815 /* Create a tempfile and write some text to it.
2816 ....................0000000001111111.
2817 ....................1234567890123456. */
2818 const char *content
= "foo = bar.field;\n";
2819 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
2820 line_table_test
ltt (case_
);
2822 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 1);
2824 location_t line_end
= linemap_position_for_column (line_table
, 16);
2826 /* Don't attempt to run the tests if column data might be unavailable. */
2827 if (line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2830 ASSERT_STREQ (tmp
.get_filename (), LOCATION_FILE (line_end
));
2831 ASSERT_EQ (1, LOCATION_LINE (line_end
));
2832 ASSERT_EQ (16, LOCATION_COLUMN (line_end
));
2834 test_one_liner_simple_caret ();
2835 test_one_liner_caret_and_range ();
2836 test_one_liner_multiple_carets_and_ranges ();
2837 test_one_liner_fixit_insert_before ();
2838 test_one_liner_fixit_insert_after ();
2839 test_one_liner_fixit_remove ();
2840 test_one_liner_fixit_replace ();
2841 test_one_liner_fixit_replace_non_equal_range ();
2842 test_one_liner_fixit_replace_equal_secondary_range ();
2843 test_one_liner_fixit_validation_adhoc_locations ();
2844 test_one_liner_many_fixits_1 ();
2845 test_one_liner_many_fixits_2 ();
2846 test_one_liner_labels ();
2849 /* Verify that gcc_rich_location::add_location_if_nearby works. */
2852 test_add_location_if_nearby (const line_table_case
&case_
)
2854 /* Create a tempfile and write some text to it.
2855 ...000000000111111111122222222223333333333.
2856 ...123456789012345678901234567890123456789. */
2858 = ("struct same_line { double x; double y; ;\n" /* line 1. */
2859 "struct different_line\n" /* line 2. */
2861 " double x;\n" /* line 4. */
2862 " double y;\n" /* line 5. */
2863 ";\n"); /* line 6. */
2864 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
2865 line_table_test
ltt (case_
);
2867 const line_map_ordinary
*ord_map
2868 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
2869 tmp
.get_filename (), 0));
2871 linemap_line_start (line_table
, 1, 100);
2873 const location_t final_line_end
2874 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 7);
2876 /* Don't attempt to run the tests if column data might be unavailable. */
2877 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2880 /* Test of add_location_if_nearby on the same line as the
2881 primary location. */
2883 const location_t missing_close_brace_1_39
2884 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 39);
2885 const location_t matching_open_brace_1_18
2886 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 18);
2887 gcc_rich_location
richloc (missing_close_brace_1_39
);
2888 bool added
= richloc
.add_location_if_nearby (matching_open_brace_1_18
);
2889 ASSERT_TRUE (added
);
2890 ASSERT_EQ (2, richloc
.get_num_locations ());
2891 test_diagnostic_context dc
;
2892 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2894 " struct same_line { double x; double y; ;\n"
2896 pp_formatted_text (dc
.printer
));
2899 /* Test of add_location_if_nearby on a different line to the
2900 primary location. */
2902 const location_t missing_close_brace_6_1
2903 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 1);
2904 const location_t matching_open_brace_3_1
2905 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 1);
2906 gcc_rich_location
richloc (missing_close_brace_6_1
);
2907 bool added
= richloc
.add_location_if_nearby (matching_open_brace_3_1
);
2908 ASSERT_FALSE (added
);
2909 ASSERT_EQ (1, richloc
.get_num_locations ());
2913 /* Verify that we print fixits even if they only affect lines
2914 outside those covered by the ranges in the rich_location. */
2917 test_diagnostic_show_locus_fixit_lines (const line_table_case
&case_
)
2919 /* Create a tempfile and write some text to it.
2920 ...000000000111111111122222222223333333333.
2921 ...123456789012345678901234567890123456789. */
2923 = ("struct point { double x; double y; };\n" /* line 1. */
2924 "struct point origin = {x: 0.0,\n" /* line 2. */
2925 " y\n" /* line 3. */
2928 " : 0.0};\n"); /* line 6. */
2929 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
2930 line_table_test
ltt (case_
);
2932 const line_map_ordinary
*ord_map
2933 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
2934 tmp
.get_filename (), 0));
2936 linemap_line_start (line_table
, 1, 100);
2938 const location_t final_line_end
2939 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 36);
2941 /* Don't attempt to run the tests if column data might be unavailable. */
2942 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2945 /* A pair of tests for modernizing the initializers to C99-style. */
2947 /* The one-liner case (line 2). */
2949 test_diagnostic_context dc
;
2951 = linemap_position_for_line_and_column (line_table
, ord_map
, 2, 24);
2952 const location_t colon
2953 = linemap_position_for_line_and_column (line_table
, ord_map
, 2, 25);
2954 rich_location
richloc (line_table
, colon
);
2955 richloc
.add_fixit_insert_before (x
, ".");
2956 richloc
.add_fixit_replace (colon
, "=");
2957 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2959 " struct point origin = {x: 0.0,\n"
2962 pp_formatted_text (dc
.printer
));
2965 /* The multiline case. The caret for the rich_location is on line 6;
2966 verify that insertion fixit on line 3 is still printed (and that
2967 span starts are printed due to the gap between the span at line 3
2968 and that at line 6). */
2970 test_diagnostic_context dc
;
2972 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 24);
2973 const location_t colon
2974 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 25);
2975 rich_location
richloc (line_table
, colon
);
2976 richloc
.add_fixit_insert_before (y
, ".");
2977 richloc
.add_fixit_replace (colon
, "=");
2978 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2987 pp_formatted_text (dc
.printer
));
2990 /* As above, but verify the behavior of multiple line spans
2991 with line-numbering enabled. */
2994 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 24);
2995 const location_t colon
2996 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 25);
2997 rich_location
richloc (line_table
, colon
);
2998 richloc
.add_fixit_insert_before (y
, ".");
2999 richloc
.add_fixit_replace (colon
, "=");
3000 test_diagnostic_context dc
;
3001 dc
.show_line_numbers_p
= true;
3002 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3010 pp_formatted_text (dc
.printer
));
3015 /* Verify that fix-it hints are appropriately consolidated.
3017 If any fix-it hints in a rich_location involve locations beyond
3018 LINE_MAP_MAX_LOCATION_WITH_COLS, then we can't reliably apply
3019 the fix-it as a whole, so there should be none.
3021 Otherwise, verify that consecutive "replace" and "remove" fix-its
3022 are merged, and that other fix-its remain separate. */
3025 test_fixit_consolidation (const line_table_case
&case_
)
3027 line_table_test
ltt (case_
);
3029 linemap_add (line_table
, LC_ENTER
, false, "test.c", 1);
3031 const location_t c10
= linemap_position_for_column (line_table
, 10);
3032 const location_t c15
= linemap_position_for_column (line_table
, 15);
3033 const location_t c16
= linemap_position_for_column (line_table
, 16);
3034 const location_t c17
= linemap_position_for_column (line_table
, 17);
3035 const location_t c20
= linemap_position_for_column (line_table
, 20);
3036 const location_t c21
= linemap_position_for_column (line_table
, 21);
3037 const location_t caret
= c10
;
3039 /* Insert + insert. */
3041 rich_location
richloc (line_table
, caret
);
3042 richloc
.add_fixit_insert_before (c10
, "foo");
3043 richloc
.add_fixit_insert_before (c15
, "bar");
3045 if (c15
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3046 /* Bogus column info for 2nd fixit, so no fixits. */
3047 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
3049 /* They should not have been merged. */
3050 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
3053 /* Insert + replace. */
3055 rich_location
richloc (line_table
, caret
);
3056 richloc
.add_fixit_insert_before (c10
, "foo");
3057 richloc
.add_fixit_replace (source_range::from_locations (c15
, c17
),
3060 if (c17
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3061 /* Bogus column info for 2nd fixit, so no fixits. */
3062 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
3064 /* They should not have been merged. */
3065 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
3068 /* Replace + non-consecutive insert. */
3070 rich_location
richloc (line_table
, caret
);
3071 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
3073 richloc
.add_fixit_insert_before (c17
, "foo");
3075 if (c17
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3076 /* Bogus column info for 2nd fixit, so no fixits. */
3077 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
3079 /* They should not have been merged. */
3080 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
3083 /* Replace + non-consecutive replace. */
3085 rich_location
richloc (line_table
, caret
);
3086 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
3088 richloc
.add_fixit_replace (source_range::from_locations (c17
, c20
),
3091 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3092 /* Bogus column info for 2nd fixit, so no fixits. */
3093 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
3095 /* They should not have been merged. */
3096 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
3099 /* Replace + consecutive replace. */
3101 rich_location
richloc (line_table
, caret
);
3102 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
3104 richloc
.add_fixit_replace (source_range::from_locations (c16
, c20
),
3107 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3108 /* Bogus column info for 2nd fixit, so no fixits. */
3109 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
3112 /* They should have been merged into a single "replace". */
3113 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3114 const fixit_hint
*hint
= richloc
.get_fixit_hint (0);
3115 ASSERT_STREQ ("foobar", hint
->get_string ());
3116 ASSERT_EQ (c10
, hint
->get_start_loc ());
3117 ASSERT_EQ (c21
, hint
->get_next_loc ());
3121 /* Replace + consecutive removal. */
3123 rich_location
richloc (line_table
, caret
);
3124 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
3126 richloc
.add_fixit_remove (source_range::from_locations (c16
, c20
));
3128 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3129 /* Bogus column info for 2nd fixit, so no fixits. */
3130 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
3133 /* They should have been merged into a single replace, with the
3134 range extended to cover that of the removal. */
3135 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3136 const fixit_hint
*hint
= richloc
.get_fixit_hint (0);
3137 ASSERT_STREQ ("foo", hint
->get_string ());
3138 ASSERT_EQ (c10
, hint
->get_start_loc ());
3139 ASSERT_EQ (c21
, hint
->get_next_loc ());
3143 /* Consecutive removals. */
3145 rich_location
richloc (line_table
, caret
);
3146 richloc
.add_fixit_remove (source_range::from_locations (c10
, c15
));
3147 richloc
.add_fixit_remove (source_range::from_locations (c16
, c20
));
3149 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3150 /* Bogus column info for 2nd fixit, so no fixits. */
3151 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
3154 /* They should have been merged into a single "replace-with-empty". */
3155 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3156 const fixit_hint
*hint
= richloc
.get_fixit_hint (0);
3157 ASSERT_STREQ ("", hint
->get_string ());
3158 ASSERT_EQ (c10
, hint
->get_start_loc ());
3159 ASSERT_EQ (c21
, hint
->get_next_loc ());
3164 /* Verify that the line_corrections machinery correctly prints
3165 overlapping fixit-hints. */
3168 test_overlapped_fixit_printing (const line_table_case
&case_
)
3170 /* Create a tempfile and write some text to it.
3171 ...000000000111111111122222222223333333333.
3172 ...123456789012345678901234567890123456789. */
3174 = (" foo *f = (foo *)ptr->field;\n");
3175 temp_source_file
tmp (SELFTEST_LOCATION
, ".C", content
);
3176 line_table_test
ltt (case_
);
3178 const line_map_ordinary
*ord_map
3179 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
3180 tmp
.get_filename (), 0));
3182 linemap_line_start (line_table
, 1, 100);
3184 const location_t final_line_end
3185 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 36);
3187 /* Don't attempt to run the tests if column data might be unavailable. */
3188 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3191 /* A test for converting a C-style cast to a C++-style cast. */
3192 const location_t open_paren
3193 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 12);
3194 const location_t close_paren
3195 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 18);
3196 const location_t expr_start
3197 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 19);
3198 const location_t expr_finish
3199 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 28);
3200 const location_t expr
= make_location (expr_start
, expr_start
, expr_finish
);
3202 /* Various examples of fix-it hints that aren't themselves consolidated,
3203 but for which the *printing* may need consolidation. */
3205 /* Example where 3 fix-it hints are printed as one. */
3207 test_diagnostic_context dc
;
3208 rich_location
richloc (line_table
, expr
);
3209 richloc
.add_fixit_replace (open_paren
, "const_cast<");
3210 richloc
.add_fixit_replace (close_paren
, "> (");
3211 richloc
.add_fixit_insert_after (")");
3213 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3215 " foo *f = (foo *)ptr->field;\n"
3217 " -----------------\n"
3218 " const_cast<foo *> (ptr->field)\n",
3219 pp_formatted_text (dc
.printer
));
3221 /* Unit-test the line_corrections machinery. */
3222 ASSERT_EQ (3, richloc
.get_num_fixit_hints ());
3223 const fixit_hint
*hint_0
= richloc
.get_fixit_hint (0);
3224 ASSERT_EQ (column_range (12, 12), get_affected_columns (hint_0
));
3225 ASSERT_EQ (column_range (12, 22), get_printed_columns (hint_0
));
3226 const fixit_hint
*hint_1
= richloc
.get_fixit_hint (1);
3227 ASSERT_EQ (column_range (18, 18), get_affected_columns (hint_1
));
3228 ASSERT_EQ (column_range (18, 20), get_printed_columns (hint_1
));
3229 const fixit_hint
*hint_2
= richloc
.get_fixit_hint (2);
3230 ASSERT_EQ (column_range (29, 28), get_affected_columns (hint_2
));
3231 ASSERT_EQ (column_range (29, 29), get_printed_columns (hint_2
));
3233 /* Add each hint in turn to a line_corrections instance,
3234 and verify that they are consolidated into one correction instance
3236 line_corrections
lc (tmp
.get_filename (), 1);
3238 /* The first replace hint by itself. */
3239 lc
.add_hint (hint_0
);
3240 ASSERT_EQ (1, lc
.m_corrections
.length ());
3241 ASSERT_EQ (column_range (12, 12), lc
.m_corrections
[0]->m_affected_columns
);
3242 ASSERT_EQ (column_range (12, 22), lc
.m_corrections
[0]->m_printed_columns
);
3243 ASSERT_STREQ ("const_cast<", lc
.m_corrections
[0]->m_text
);
3245 /* After the second replacement hint, they are printed together
3246 as a replacement (along with the text between them). */
3247 lc
.add_hint (hint_1
);
3248 ASSERT_EQ (1, lc
.m_corrections
.length ());
3249 ASSERT_STREQ ("const_cast<foo *> (", lc
.m_corrections
[0]->m_text
);
3250 ASSERT_EQ (column_range (12, 18), lc
.m_corrections
[0]->m_affected_columns
);
3251 ASSERT_EQ (column_range (12, 30), lc
.m_corrections
[0]->m_printed_columns
);
3253 /* After the final insertion hint, they are all printed together
3254 as a replacement (along with the text between them). */
3255 lc
.add_hint (hint_2
);
3256 ASSERT_STREQ ("const_cast<foo *> (ptr->field)",
3257 lc
.m_corrections
[0]->m_text
);
3258 ASSERT_EQ (1, lc
.m_corrections
.length ());
3259 ASSERT_EQ (column_range (12, 28), lc
.m_corrections
[0]->m_affected_columns
);
3260 ASSERT_EQ (column_range (12, 41), lc
.m_corrections
[0]->m_printed_columns
);
3263 /* Example where two are consolidated during printing. */
3265 test_diagnostic_context dc
;
3266 rich_location
richloc (line_table
, expr
);
3267 richloc
.add_fixit_replace (open_paren
, "CAST (");
3268 richloc
.add_fixit_replace (close_paren
, ") (");
3269 richloc
.add_fixit_insert_after (")");
3271 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3273 " foo *f = (foo *)ptr->field;\n"
3278 pp_formatted_text (dc
.printer
));
3281 /* Example where none are consolidated during printing. */
3283 test_diagnostic_context dc
;
3284 rich_location
richloc (line_table
, expr
);
3285 richloc
.add_fixit_replace (open_paren
, "CST (");
3286 richloc
.add_fixit_replace (close_paren
, ") (");
3287 richloc
.add_fixit_insert_after (")");
3289 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3291 " foo *f = (foo *)ptr->field;\n"
3296 pp_formatted_text (dc
.printer
));
3299 /* Example of deletion fix-it hints. */
3301 test_diagnostic_context dc
;
3302 rich_location
richloc (line_table
, expr
);
3303 richloc
.add_fixit_insert_before (open_paren
, "(bar *)");
3304 source_range victim
= {open_paren
, close_paren
};
3305 richloc
.add_fixit_remove (victim
);
3307 /* This case is actually handled by fixit-consolidation,
3308 rather than by line_corrections. */
3309 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3311 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3313 " foo *f = (foo *)ptr->field;\n"
3317 pp_formatted_text (dc
.printer
));
3320 /* Example of deletion fix-it hints that would overlap. */
3322 test_diagnostic_context dc
;
3323 rich_location
richloc (line_table
, expr
);
3324 richloc
.add_fixit_insert_before (open_paren
, "(longer *)");
3325 source_range victim
= {expr_start
, expr_finish
};
3326 richloc
.add_fixit_remove (victim
);
3328 /* These fixits are not consolidated. */
3329 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
3331 /* But the corrections are. */
3332 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3334 " foo *f = (foo *)ptr->field;\n"
3336 " -----------------\n"
3337 " (longer *)(foo *)\n",
3338 pp_formatted_text (dc
.printer
));
3341 /* Example of insertion fix-it hints that would overlap. */
3343 test_diagnostic_context dc
;
3344 rich_location
richloc (line_table
, expr
);
3345 richloc
.add_fixit_insert_before (open_paren
, "LONGER THAN THE CAST");
3346 richloc
.add_fixit_insert_after (close_paren
, "TEST");
3348 /* The first insertion is long enough that if printed naively,
3349 it would overlap with the second.
3350 Verify that they are printed as a single replacement. */
3351 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3353 " foo *f = (foo *)ptr->field;\n"
3356 " LONGER THAN THE CAST(foo *)TEST\n",
3357 pp_formatted_text (dc
.printer
));
3361 /* Verify that the line_corrections machinery correctly prints
3362 overlapping fixit-hints that have been added in the wrong
3364 Adapted from PR c/81405 seen on gcc.dg/init-excess-1.c*/
3367 test_overlapped_fixit_printing_2 (const line_table_case
&case_
)
3369 /* Create a tempfile and write some text to it.
3370 ...000000000111111111122222222223333333333.
3371 ...123456789012345678901234567890123456789. */
3373 = ("int a5[][0][0] = { 1, 2 };\n");
3374 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
3375 line_table_test
ltt (case_
);
3377 const line_map_ordinary
*ord_map
3378 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
3379 tmp
.get_filename (), 0));
3381 linemap_line_start (line_table
, 1, 100);
3383 const location_t final_line_end
3384 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 100);
3386 /* Don't attempt to run the tests if column data might be unavailable. */
3387 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3390 const location_t col_1
3391 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 1);
3392 const location_t col_20
3393 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 20);
3394 const location_t col_21
3395 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 21);
3396 const location_t col_23
3397 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 23);
3398 const location_t col_25
3399 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 25);
3401 /* Two insertions, in the wrong order. */
3403 rich_location
richloc (line_table
, col_20
);
3404 richloc
.add_fixit_insert_before (col_23
, "{");
3405 richloc
.add_fixit_insert_before (col_21
, "}");
3407 /* These fixits should be accepted; they can't be consolidated. */
3408 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
3409 const fixit_hint
*hint_0
= richloc
.get_fixit_hint (0);
3410 ASSERT_EQ (column_range (23, 22), get_affected_columns (hint_0
));
3411 ASSERT_EQ (column_range (23, 23), get_printed_columns (hint_0
));
3412 const fixit_hint
*hint_1
= richloc
.get_fixit_hint (1);
3413 ASSERT_EQ (column_range (21, 20), get_affected_columns (hint_1
));
3414 ASSERT_EQ (column_range (21, 21), get_printed_columns (hint_1
));
3416 /* Verify that they're printed correctly. */
3417 test_diagnostic_context dc
;
3418 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3420 " int a5[][0][0] = { 1, 2 };\n"
3423 pp_formatted_text (dc
.printer
));
3426 /* Various overlapping insertions, some occurring "out of order"
3427 (reproducing the fix-it hints from PR c/81405). */
3429 test_diagnostic_context dc
;
3430 rich_location
richloc (line_table
, col_20
);
3432 richloc
.add_fixit_insert_before (col_20
, "{{");
3433 richloc
.add_fixit_insert_before (col_21
, "}}");
3434 richloc
.add_fixit_insert_before (col_23
, "{");
3435 richloc
.add_fixit_insert_before (col_21
, "}");
3436 richloc
.add_fixit_insert_before (col_23
, "{{");
3437 richloc
.add_fixit_insert_before (col_25
, "}");
3438 richloc
.add_fixit_insert_before (col_21
, "}");
3439 richloc
.add_fixit_insert_before (col_1
, "{");
3440 richloc
.add_fixit_insert_before (col_25
, "}");
3441 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3443 " int a5[][0][0] = { 1, 2 };\n"
3446 " {{1}}}}, {{{2 }}\n",
3447 pp_formatted_text (dc
.printer
));
3451 /* Insertion fix-it hint: adding a "break;" on a line by itself. */
3454 test_fixit_insert_containing_newline (const line_table_case
&case_
)
3456 /* Create a tempfile and write some text to it.
3457 .........................0000000001111111.
3458 .........................1234567890123456. */
3459 const char *old_content
= (" case 'a':\n" /* line 1. */
3460 " x = a;\n" /* line 2. */
3461 " case 'b':\n" /* line 3. */
3462 " x = b;\n");/* line 4. */
3464 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
3465 line_table_test
ltt (case_
);
3466 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 3);
3468 location_t case_start
= linemap_position_for_column (line_table
, 5);
3469 location_t case_finish
= linemap_position_for_column (line_table
, 13);
3470 location_t case_loc
= make_location (case_start
, case_start
, case_finish
);
3471 location_t line_start
= linemap_position_for_column (line_table
, 1);
3473 if (case_finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3476 /* Add a "break;" on a line by itself before line 3 i.e. before
3477 column 1 of line 3. */
3479 rich_location
richloc (line_table
, case_loc
);
3480 richloc
.add_fixit_insert_before (line_start
, " break;\n");
3482 /* Without line numbers. */
3484 test_diagnostic_context dc
;
3485 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3491 pp_formatted_text (dc
.printer
));
3494 /* With line numbers. */
3496 test_diagnostic_context dc
;
3497 dc
.show_line_numbers_p
= true;
3498 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3504 pp_formatted_text (dc
.printer
));
3508 /* Verify that attempts to add text with a newline fail when the
3509 insertion point is *not* at the start of a line. */
3511 rich_location
richloc (line_table
, case_loc
);
3512 richloc
.add_fixit_insert_before (case_start
, "break;\n");
3513 ASSERT_TRUE (richloc
.seen_impossible_fixit_p ());
3514 test_diagnostic_context dc
;
3515 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3519 pp_formatted_text (dc
.printer
));
3523 /* Insertion fix-it hint: adding a "#include <stdio.h>\n" to the top
3524 of the file, where the fix-it is printed in a different line-span
3525 to the primary range of the diagnostic. */
3528 test_fixit_insert_containing_newline_2 (const line_table_case
&case_
)
3530 /* Create a tempfile and write some text to it.
3531 .........................0000000001111111.
3532 .........................1234567890123456. */
3533 const char *old_content
= ("test (int ch)\n" /* line 1. */
3535 " putchar (ch);\n" /* line 3. */
3536 "}\n"); /* line 4. */
3538 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
3539 line_table_test
ltt (case_
);
3541 const line_map_ordinary
*ord_map
= linemap_check_ordinary
3542 (linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 0));
3543 linemap_line_start (line_table
, 1, 100);
3545 /* The primary range is the "putchar" token. */
3546 location_t putchar_start
3547 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 2);
3548 location_t putchar_finish
3549 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 8);
3550 location_t putchar_loc
3551 = make_location (putchar_start
, putchar_start
, putchar_finish
);
3552 rich_location
richloc (line_table
, putchar_loc
);
3554 /* Add a "#include <stdio.h>" on a line by itself at the top of the file. */
3555 location_t file_start
3556 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 1);
3557 richloc
.add_fixit_insert_before (file_start
, "#include <stdio.h>\n");
3559 if (putchar_finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3563 test_diagnostic_context dc
;
3564 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3567 "+#include <stdio.h>\n"
3572 pp_formatted_text (dc
.printer
));
3575 /* With line-numbering, the line spans are close enough to be
3576 consolidated, since it makes little sense to skip line 2. */
3578 test_diagnostic_context dc
;
3579 dc
.show_line_numbers_p
= true;
3580 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3582 " +++ |+#include <stdio.h>\n"
3583 " 1 | test (int ch)\n"
3585 " 3 | putchar (ch);\n"
3587 pp_formatted_text (dc
.printer
));
3591 /* Replacement fix-it hint containing a newline.
3592 This will fail, as newlines are only supported when inserting at the
3593 beginning of a line. */
3596 test_fixit_replace_containing_newline (const line_table_case
&case_
)
3598 /* Create a tempfile and write some text to it.
3599 .........................0000000001111.
3600 .........................1234567890123. */
3601 const char *old_content
= "foo = bar ();\n";
3603 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
3604 line_table_test
ltt (case_
);
3605 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 1);
3607 /* Replace the " = " with "\n = ", as if we were reformatting an
3608 overly long line. */
3609 location_t start
= linemap_position_for_column (line_table
, 4);
3610 location_t finish
= linemap_position_for_column (line_table
, 6);
3611 location_t loc
= linemap_position_for_column (line_table
, 13);
3612 rich_location
richloc (line_table
, loc
);
3613 source_range range
= source_range::from_locations (start
, finish
);
3614 richloc
.add_fixit_replace (range
, "\n =");
3616 /* Arbitrary newlines are not yet supported within fix-it hints, so
3617 the fix-it should not be displayed. */
3618 ASSERT_TRUE (richloc
.seen_impossible_fixit_p ());
3620 if (finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3623 test_diagnostic_context dc
;
3624 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3628 pp_formatted_text (dc
.printer
));
3631 /* Fix-it hint, attempting to delete a newline.
3632 This will fail, as we currently only support fix-it hints that
3633 affect one line at a time. */
3636 test_fixit_deletion_affecting_newline (const line_table_case
&case_
)
3638 /* Create a tempfile and write some text to it.
3639 ..........................0000000001111.
3640 ..........................1234567890123. */
3641 const char *old_content
= ("foo = bar (\n"
3644 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
3645 line_table_test
ltt (case_
);
3646 const line_map_ordinary
*ord_map
= linemap_check_ordinary
3647 (linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 0));
3648 linemap_line_start (line_table
, 1, 100);
3650 /* Attempt to delete the " (\n...)". */
3652 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 10);
3654 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 11);
3656 = linemap_position_for_line_and_column (line_table
, ord_map
, 2, 7);
3657 location_t loc
= make_location (caret
, start
, finish
);
3658 rich_location
richloc (line_table
, loc
);
3659 richloc
. add_fixit_remove ();
3661 /* Fix-it hints that affect more than one line are not yet supported, so
3662 the fix-it should not be displayed. */
3663 ASSERT_TRUE (richloc
.seen_impossible_fixit_p ());
3665 if (finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3668 test_diagnostic_context dc
;
3669 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3675 pp_formatted_text (dc
.printer
));
3678 /* Verify that line numbers are correctly printed for the case of
3679 a multiline range in which the width of the line numbers changes
3680 (e.g. from "9" to "10"). */
3683 test_line_numbers_multiline_range ()
3685 /* Create a tempfile and write some text to it. */
3687 for (int i
= 0; i
< 20; i
++)
3688 /* .........0000000001111111.
3689 .............1234567890123456. */
3690 pp_printf (&pp
, "this is line %i\n", i
+ 1);
3691 temp_source_file
tmp (SELFTEST_LOCATION
, ".txt", pp_formatted_text (&pp
));
3692 line_table_test ltt
;
3694 const line_map_ordinary
*ord_map
= linemap_check_ordinary
3695 (linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 0));
3696 linemap_line_start (line_table
, 1, 100);
3698 /* Create a multi-line location, starting at the "line" of line 9, with
3699 a caret on the "is" of line 10, finishing on the "this" line 11. */
3702 = linemap_position_for_line_and_column (line_table
, ord_map
, 9, 9);
3704 = linemap_position_for_line_and_column (line_table
, ord_map
, 10, 6);
3706 = linemap_position_for_line_and_column (line_table
, ord_map
, 11, 4);
3707 location_t loc
= make_location (caret
, start
, finish
);
3709 test_diagnostic_context dc
;
3710 dc
.show_line_numbers_p
= true;
3711 dc
.min_margin_width
= 0;
3712 gcc_rich_location
richloc (loc
);
3713 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3715 " 9 | this is line 9\n"
3717 "10 | this is line 10\n"
3718 " | ~~~~~^~~~~~~~~~\n"
3719 "11 | this is line 11\n"
3721 pp_formatted_text (dc
.printer
));
3724 /* Run all of the selftests within this file. */
3727 diagnostic_show_locus_c_tests ()
3731 test_layout_range_for_single_point ();
3732 test_layout_range_for_single_line ();
3733 test_layout_range_for_multiple_lines ();
3735 test_get_line_width_without_trailing_whitespace ();
3737 test_diagnostic_show_locus_unknown_location ();
3739 for_each_line_table_case (test_diagnostic_show_locus_one_liner
);
3740 for_each_line_table_case (test_add_location_if_nearby
);
3741 for_each_line_table_case (test_diagnostic_show_locus_fixit_lines
);
3742 for_each_line_table_case (test_fixit_consolidation
);
3743 for_each_line_table_case (test_overlapped_fixit_printing
);
3744 for_each_line_table_case (test_overlapped_fixit_printing_2
);
3745 for_each_line_table_case (test_fixit_insert_containing_newline
);
3746 for_each_line_table_case (test_fixit_insert_containing_newline_2
);
3747 for_each_line_table_case (test_fixit_replace_containing_newline
);
3748 for_each_line_table_case (test_fixit_deletion_affecting_newline
);
3750 test_line_numbers_multiline_range ();
3753 } // namespace selftest
3755 #endif /* #if CHECKING_P */
3758 # pragma GCC diagnostic pop