1 /* Diagnostic subroutines for printing source-code
2 Copyright (C) 1999-2018 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 /* Classes for rendering source code and diagnostics, within an
44 The work is done by "class layout", which embeds and uses
45 "class colorizer" and "class layout_range" to get things done. */
49 /* The state at a given point of the source code, assuming that we're
50 in a range: which range are we in, and whether we should draw a caret at
59 /* A class to inject colorization codes when printing the diagnostic locus.
61 It has one kind of colorization for each of:
63 - range 0 (the "primary location")
67 The class caches the lookup of the color codes for the above.
69 The class also has responsibility for tracking which of the above is
70 active, filtering out unnecessary changes. This allows
71 layout::print_source_line and layout::print_annotation_line
72 to simply request a colorization code for *every* character they print,
73 via this class, and have the filtering be done for them here. */
78 colorizer (diagnostic_context
*context
,
79 diagnostic_t diagnostic_kind
);
82 void set_range (int range_idx
) { set_state (range_idx
); }
83 void set_normal_text () { set_state (STATE_NORMAL_TEXT
); }
84 void set_fixit_insert () { set_state (STATE_FIXIT_INSERT
); }
85 void set_fixit_delete () { set_state (STATE_FIXIT_DELETE
); }
88 void set_state (int state
);
89 void begin_state (int state
);
90 void finish_state (int state
);
91 const char *get_color_by_name (const char *);
94 static const int STATE_NORMAL_TEXT
= -1;
95 static const int STATE_FIXIT_INSERT
= -2;
96 static const int STATE_FIXIT_DELETE
= -3;
98 diagnostic_context
*m_context
;
99 diagnostic_t m_diagnostic_kind
;
101 const char *m_range1
;
102 const char *m_range2
;
103 const char *m_fixit_insert
;
104 const char *m_fixit_delete
;
105 const char *m_stop_color
;
108 /* A point within a layout_range; similar to an expanded_location,
109 but after filtering on file. */
114 layout_point (const expanded_location
&exploc
)
115 : m_line (exploc
.line
),
116 m_column (exploc
.column
) {}
122 /* A class for use by "class layout" below: a filtered location_range. */
127 layout_range (const expanded_location
*start_exploc
,
128 const expanded_location
*finish_exploc
,
130 const expanded_location
*caret_exploc
);
132 bool contains_point (linenum_type row
, int column
) const;
133 bool intersects_line_p (linenum_type row
) const;
135 layout_point m_start
;
136 layout_point m_finish
;
138 layout_point m_caret
;
141 /* A struct for use by layout::print_source_line for telling
142 layout::print_annotation_line the extents of the source line that
143 it printed, so that underlines can be clipped appropriately. */
151 /* A range of contiguous source lines within a layout (e.g. "lines 5-10"
152 or "line 23"). During the layout ctor, layout::calculate_line_spans
153 splits the pertinent source lines into a list of disjoint line_span
154 instances (e.g. lines 5-10, lines 15-20, line 23). */
158 line_span (linenum_type first_line
, linenum_type last_line
)
159 : m_first_line (first_line
), m_last_line (last_line
)
161 gcc_assert (first_line
<= last_line
);
163 linenum_type
get_first_line () const { return m_first_line
; }
164 linenum_type
get_last_line () const { return m_last_line
; }
166 bool contains_line_p (linenum_type line
) const
168 return line
>= m_first_line
&& line
<= m_last_line
;
171 static int comparator (const void *p1
, const void *p2
)
173 const line_span
*ls1
= (const line_span
*)p1
;
174 const line_span
*ls2
= (const line_span
*)p2
;
175 int first_line_cmp
= compare (ls1
->m_first_line
, ls2
->m_first_line
);
177 return first_line_cmp
;
178 return compare (ls1
->m_last_line
, ls2
->m_last_line
);
181 linenum_type m_first_line
;
182 linenum_type m_last_line
;
187 /* Selftests for line_span. */
192 line_span
line_one (1, 1);
193 ASSERT_EQ (1, line_one
.get_first_line ());
194 ASSERT_EQ (1, line_one
.get_last_line ());
195 ASSERT_FALSE (line_one
.contains_line_p (0));
196 ASSERT_TRUE (line_one
.contains_line_p (1));
197 ASSERT_FALSE (line_one
.contains_line_p (2));
199 line_span
lines_1_to_3 (1, 3);
200 ASSERT_EQ (1, lines_1_to_3
.get_first_line ());
201 ASSERT_EQ (3, lines_1_to_3
.get_last_line ());
202 ASSERT_TRUE (lines_1_to_3
.contains_line_p (1));
203 ASSERT_TRUE (lines_1_to_3
.contains_line_p (3));
205 ASSERT_EQ (0, line_span::comparator (&line_one
, &line_one
));
206 ASSERT_GT (line_span::comparator (&lines_1_to_3
, &line_one
), 0);
207 ASSERT_LT (line_span::comparator (&line_one
, &lines_1_to_3
), 0);
209 /* A linenum > 2^31. */
210 const linenum_type LARGEST_LINE
= 0xffffffff;
211 line_span
largest_line (LARGEST_LINE
, LARGEST_LINE
);
212 ASSERT_EQ (LARGEST_LINE
, largest_line
.get_first_line ());
213 ASSERT_EQ (LARGEST_LINE
, largest_line
.get_last_line ());
215 ASSERT_GT (line_span::comparator (&largest_line
, &line_one
), 0);
216 ASSERT_LT (line_span::comparator (&line_one
, &largest_line
), 0);
219 #endif /* #if CHECKING_P */
221 /* A class to control the overall layout when printing a diagnostic.
223 The layout is determined within the constructor.
224 It is then printed by repeatedly calling the "print_source_line",
225 "print_annotation_line" and "print_any_fixits" methods.
227 We assume we have disjoint ranges. */
232 layout (diagnostic_context
*context
,
233 rich_location
*richloc
,
234 diagnostic_t diagnostic_kind
);
236 bool maybe_add_location_range (const location_range
*loc_range
,
237 bool restrict_to_current_line_spans
);
239 int get_num_line_spans () const { return m_line_spans
.length (); }
240 const line_span
*get_line_span (int idx
) const { return &m_line_spans
[idx
]; }
242 bool print_heading_for_line_span_index_p (int line_span_idx
) const;
244 expanded_location
get_expanded_location (const line_span
*) const;
246 void print_line (linenum_type row
);
249 bool will_show_line_p (linenum_type row
) const;
250 void print_leading_fixits (linenum_type row
);
251 void print_source_line (linenum_type row
, const char *line
, int line_width
,
252 line_bounds
*lbounds_out
);
253 bool should_print_annotation_line_p (linenum_type row
) const;
254 void print_annotation_line (linenum_type row
, const line_bounds lbounds
);
255 void print_trailing_fixits (linenum_type row
);
257 bool annotation_line_showed_range_p (linenum_type line
, int start_column
,
258 int finish_column
) const;
259 void show_ruler (int max_column
) const;
261 bool validate_fixit_hint_p (const fixit_hint
*hint
);
263 void calculate_line_spans ();
265 void print_newline ();
268 get_state_at_point (/* Inputs. */
269 linenum_type row
, int column
,
270 int first_non_ws
, int last_non_ws
,
272 point_state
*out_state
);
275 get_x_bound_for_row (linenum_type row
, int caret_column
,
279 move_to_column (int *column
, int dest_column
);
282 diagnostic_context
*m_context
;
283 pretty_printer
*m_pp
;
284 diagnostic_t m_diagnostic_kind
;
285 location_t m_primary_loc
;
286 expanded_location m_exploc
;
287 colorizer m_colorizer
;
288 bool m_colorize_source_p
;
289 auto_vec
<layout_range
> m_layout_ranges
;
290 auto_vec
<const fixit_hint
*> m_fixit_hints
;
291 auto_vec
<line_span
> m_line_spans
;
295 /* Implementation of "class colorizer". */
297 /* The constructor for "colorizer". Lookup and store color codes for the
298 different kinds of things we might need to print. */
300 colorizer::colorizer (diagnostic_context
*context
,
301 diagnostic_t diagnostic_kind
) :
303 m_diagnostic_kind (diagnostic_kind
),
304 m_current_state (STATE_NORMAL_TEXT
)
306 m_range1
= get_color_by_name ("range1");
307 m_range2
= get_color_by_name ("range2");
308 m_fixit_insert
= get_color_by_name ("fixit-insert");
309 m_fixit_delete
= get_color_by_name ("fixit-delete");
310 m_stop_color
= colorize_stop (pp_show_color (context
->printer
));
313 /* The destructor for "colorize". If colorization is on, print a code to
316 colorizer::~colorizer ()
318 finish_state (m_current_state
);
321 /* Update state, printing color codes if necessary if there's a state
325 colorizer::set_state (int new_state
)
327 if (m_current_state
!= new_state
)
329 finish_state (m_current_state
);
330 m_current_state
= new_state
;
331 begin_state (new_state
);
335 /* Turn on any colorization for STATE. */
338 colorizer::begin_state (int state
)
342 case STATE_NORMAL_TEXT
:
345 case STATE_FIXIT_INSERT
:
346 pp_string (m_context
->printer
, m_fixit_insert
);
349 case STATE_FIXIT_DELETE
:
350 pp_string (m_context
->printer
, m_fixit_delete
);
354 /* Make range 0 be the same color as the "kind" text
355 (error vs warning vs note). */
358 colorize_start (pp_show_color (m_context
->printer
),
359 diagnostic_get_color_for_kind (m_diagnostic_kind
)));
363 pp_string (m_context
->printer
, m_range1
);
367 pp_string (m_context
->printer
, m_range2
);
371 /* For ranges beyond 2, alternate between color 1 and color 2. */
373 gcc_assert (state
> 2);
374 pp_string (m_context
->printer
,
375 state
% 2 ? m_range1
: m_range2
);
381 /* Turn off any colorization for STATE. */
384 colorizer::finish_state (int state
)
386 if (state
!= STATE_NORMAL_TEXT
)
387 pp_string (m_context
->printer
, m_stop_color
);
390 /* Get the color code for NAME (or the empty string if
391 colorization is disabled). */
394 colorizer::get_color_by_name (const char *name
)
396 return colorize_start (pp_show_color (m_context
->printer
), name
);
399 /* Implementation of class layout_range. */
401 /* The constructor for class layout_range.
402 Initialize various layout_point fields from expanded_location
403 equivalents; we've already filtered on file. */
405 layout_range::layout_range (const expanded_location
*start_exploc
,
406 const expanded_location
*finish_exploc
,
408 const expanded_location
*caret_exploc
)
409 : m_start (*start_exploc
),
410 m_finish (*finish_exploc
),
411 m_show_caret_p (show_caret_p
),
412 m_caret (*caret_exploc
)
416 /* Is (column, row) within the given range?
417 We've already filtered on the file.
419 Ranges are closed (both limits are within the range).
421 Example A: a single-line range:
422 start: (col=22, line=2)
423 finish: (col=38, line=2)
425 |00000011111111112222222222333333333344444444444
426 |34567890123456789012345678901234567890123456789
427 --+-----------------------------------------------
428 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
429 02|bbbbbbbbbbbbbbbbbbbSwwwwwwwwwwwwwwwFaaaaaaaaaaa
430 03|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
432 Example B: a multiline range with
433 start: (col=14, line=3)
434 finish: (col=08, line=5)
436 |00000011111111112222222222333333333344444444444
437 |34567890123456789012345678901234567890123456789
438 --+-----------------------------------------------
439 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
440 02|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
441 03|bbbbbbbbbbbSwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
442 04|wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
443 05|wwwwwFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
444 06|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
445 --+-----------------------------------------------
448 - 'b' indicates a point *before* the range
449 - 'S' indicates the start of the range
450 - 'w' indicates a point within the range
451 - 'F' indicates the finish of the range (which is
453 - 'a' indicates a subsequent point *after* the range. */
456 layout_range::contains_point (linenum_type row
, int column
) const
458 gcc_assert (m_start
.m_line
<= m_finish
.m_line
);
459 /* ...but the equivalent isn't true for the columns;
460 consider example B in the comment above. */
462 if (row
< m_start
.m_line
)
463 /* Points before the first line of the range are
464 outside it (corresponding to line 01 in example A
465 and lines 01 and 02 in example B above). */
468 if (row
== m_start
.m_line
)
469 /* On same line as start of range (corresponding
470 to line 02 in example A and line 03 in example B). */
472 if (column
< m_start
.m_column
)
473 /* Points on the starting line of the range, but
474 before the column in which it begins. */
477 if (row
< m_finish
.m_line
)
478 /* This is a multiline range; the point
479 is within it (corresponds to line 03 in example B
480 from column 14 onwards) */
484 /* This is a single-line range. */
485 gcc_assert (row
== m_finish
.m_line
);
486 return column
<= m_finish
.m_column
;
490 /* The point is in a line beyond that containing the
491 start of the range: lines 03 onwards in example A,
492 and lines 04 onwards in example B. */
493 gcc_assert (row
> m_start
.m_line
);
495 if (row
> m_finish
.m_line
)
496 /* The point is beyond the final line of the range
497 (lines 03 onwards in example A, and lines 06 onwards
501 if (row
< m_finish
.m_line
)
503 /* The point is in a line that's fully within a multiline
504 range (e.g. line 04 in example B). */
505 gcc_assert (m_start
.m_line
< m_finish
.m_line
);
509 gcc_assert (row
== m_finish
.m_line
);
511 return column
<= m_finish
.m_column
;
514 /* Does this layout_range contain any part of line ROW? */
517 layout_range::intersects_line_p (linenum_type row
) const
519 gcc_assert (m_start
.m_line
<= m_finish
.m_line
);
520 if (row
< m_start
.m_line
)
522 if (row
> m_finish
.m_line
)
529 /* A helper function for testing layout_range. */
532 make_range (int start_line
, int start_col
, int end_line
, int end_col
)
534 const expanded_location start_exploc
535 = {"test.c", start_line
, start_col
, NULL
, false};
536 const expanded_location finish_exploc
537 = {"test.c", end_line
, end_col
, NULL
, false};
538 return layout_range (&start_exploc
, &finish_exploc
, false,
542 /* Selftests for layout_range::contains_point and
543 layout_range::intersects_line_p. */
545 /* Selftest for layout_range, where the layout_range
546 is a range with start==end i.e. a single point. */
549 test_layout_range_for_single_point ()
551 layout_range point
= make_range (7, 10, 7, 10);
553 /* Tests for layout_range::contains_point. */
555 /* Before the line. */
556 ASSERT_FALSE (point
.contains_point (6, 1));
558 /* On the line, but before start. */
559 ASSERT_FALSE (point
.contains_point (7, 9));
562 ASSERT_TRUE (point
.contains_point (7, 10));
564 /* On the line, after the point. */
565 ASSERT_FALSE (point
.contains_point (7, 11));
567 /* After the line. */
568 ASSERT_FALSE (point
.contains_point (8, 1));
570 /* Tests for layout_range::intersects_line_p. */
571 ASSERT_FALSE (point
.intersects_line_p (6));
572 ASSERT_TRUE (point
.intersects_line_p (7));
573 ASSERT_FALSE (point
.intersects_line_p (8));
576 /* Selftest for layout_range, where the layout_range
577 is the single-line range shown as "Example A" above. */
580 test_layout_range_for_single_line ()
582 layout_range example_a
= make_range (2, 22, 2, 38);
584 /* Tests for layout_range::contains_point. */
586 /* Before the line. */
587 ASSERT_FALSE (example_a
.contains_point (1, 1));
589 /* On the line, but before start. */
590 ASSERT_FALSE (example_a
.contains_point (2, 21));
592 /* On the line, at the start. */
593 ASSERT_TRUE (example_a
.contains_point (2, 22));
595 /* On the line, within the range. */
596 ASSERT_TRUE (example_a
.contains_point (2, 23));
598 /* On the line, at the end. */
599 ASSERT_TRUE (example_a
.contains_point (2, 38));
601 /* On the line, after the end. */
602 ASSERT_FALSE (example_a
.contains_point (2, 39));
604 /* After the line. */
605 ASSERT_FALSE (example_a
.contains_point (2, 39));
607 /* Tests for layout_range::intersects_line_p. */
608 ASSERT_FALSE (example_a
.intersects_line_p (1));
609 ASSERT_TRUE (example_a
.intersects_line_p (2));
610 ASSERT_FALSE (example_a
.intersects_line_p (3));
613 /* Selftest for layout_range, where the layout_range
614 is the multi-line range shown as "Example B" above. */
617 test_layout_range_for_multiple_lines ()
619 layout_range example_b
= make_range (3, 14, 5, 8);
621 /* Tests for layout_range::contains_point. */
623 /* Before first line. */
624 ASSERT_FALSE (example_b
.contains_point (1, 1));
626 /* On the first line, but before start. */
627 ASSERT_FALSE (example_b
.contains_point (3, 13));
630 ASSERT_TRUE (example_b
.contains_point (3, 14));
632 /* On the first line, within the range. */
633 ASSERT_TRUE (example_b
.contains_point (3, 15));
635 /* On an interior line.
636 The column number should not matter; try various boundary
638 ASSERT_TRUE (example_b
.contains_point (4, 1));
639 ASSERT_TRUE (example_b
.contains_point (4, 7));
640 ASSERT_TRUE (example_b
.contains_point (4, 8));
641 ASSERT_TRUE (example_b
.contains_point (4, 9));
642 ASSERT_TRUE (example_b
.contains_point (4, 13));
643 ASSERT_TRUE (example_b
.contains_point (4, 14));
644 ASSERT_TRUE (example_b
.contains_point (4, 15));
646 /* On the final line, before the end. */
647 ASSERT_TRUE (example_b
.contains_point (5, 7));
649 /* On the final line, at the end. */
650 ASSERT_TRUE (example_b
.contains_point (5, 8));
652 /* On the final line, after the end. */
653 ASSERT_FALSE (example_b
.contains_point (5, 9));
655 /* After the line. */
656 ASSERT_FALSE (example_b
.contains_point (6, 1));
658 /* Tests for layout_range::intersects_line_p. */
659 ASSERT_FALSE (example_b
.intersects_line_p (2));
660 ASSERT_TRUE (example_b
.intersects_line_p (3));
661 ASSERT_TRUE (example_b
.intersects_line_p (4));
662 ASSERT_TRUE (example_b
.intersects_line_p (5));
663 ASSERT_FALSE (example_b
.intersects_line_p (6));
666 #endif /* #if CHECKING_P */
668 /* Given a source line LINE of length LINE_WIDTH, determine the width
669 without any trailing whitespace. */
672 get_line_width_without_trailing_whitespace (const char *line
, int line_width
)
674 int result
= line_width
;
677 char ch
= line
[result
- 1];
678 if (ch
== ' ' || ch
== '\t' || ch
== '\r')
683 gcc_assert (result
>= 0);
684 gcc_assert (result
<= line_width
);
685 gcc_assert (result
== 0 ||
686 (line
[result
- 1] != ' '
687 && line
[result
-1] != '\t'
688 && line
[result
-1] != '\r'));
694 /* A helper function for testing get_line_width_without_trailing_whitespace. */
697 assert_eq (const char *line
, int expected_width
)
700 = get_line_width_without_trailing_whitespace (line
, strlen (line
));
701 ASSERT_EQ (actual_value
, expected_width
);
704 /* Verify that get_line_width_without_trailing_whitespace is sane for
705 various inputs. It is not required to handle newlines. */
708 test_get_line_width_without_trailing_whitespace ()
714 assert_eq ("hello world", 11);
715 assert_eq ("hello world ", 11);
716 assert_eq ("hello world \t\t ", 11);
717 assert_eq ("hello world\r", 11);
720 #endif /* #if CHECKING_P */
722 /* Helper function for layout's ctor, for sanitizing locations relative
723 to the primary location within a diagnostic.
725 Compare LOC_A and LOC_B to see if it makes sense to print underlines
726 connecting their expanded locations. Doing so is only guaranteed to
727 make sense if the locations share the same macro expansion "history"
728 i.e. they can be traced through the same macro expansions, eventually
729 reaching an ordinary map.
731 This may be too strong a condition, but it effectively sanitizes
732 PR c++/70105, which has an example of printing an expression where the
733 final location of the expression is in a different macro, which
734 erroneously was leading to hundreds of lines of irrelevant source
738 compatible_locations_p (location_t loc_a
, location_t loc_b
)
740 if (IS_ADHOC_LOC (loc_a
))
741 loc_a
= get_location_from_adhoc_loc (line_table
, loc_a
);
742 if (IS_ADHOC_LOC (loc_b
))
743 loc_b
= get_location_from_adhoc_loc (line_table
, loc_b
);
745 /* If either location is one of the special locations outside of a
746 linemap, they are only compatible if they are equal. */
747 if (loc_a
< RESERVED_LOCATION_COUNT
748 || loc_b
< RESERVED_LOCATION_COUNT
)
749 return loc_a
== loc_b
;
751 const line_map
*map_a
= linemap_lookup (line_table
, loc_a
);
752 linemap_assert (map_a
);
754 const line_map
*map_b
= linemap_lookup (line_table
, loc_b
);
755 linemap_assert (map_b
);
757 /* Are they within the same map? */
760 /* Are both within the same macro expansion? */
761 if (linemap_macro_expansion_map_p (map_a
))
763 /* Expand each location towards the spelling location, and
765 const line_map_macro
*macro_map
= linemap_check_macro (map_a
);
766 source_location loc_a_toward_spelling
767 = linemap_macro_map_loc_unwind_toward_spelling (line_table
,
770 source_location loc_b_toward_spelling
771 = linemap_macro_map_loc_unwind_toward_spelling (line_table
,
774 return compatible_locations_p (loc_a_toward_spelling
,
775 loc_b_toward_spelling
);
778 /* Otherwise they are within the same ordinary map. */
783 /* Within different maps. */
785 /* If either is within a macro expansion, they are incompatible. */
786 if (linemap_macro_expansion_map_p (map_a
)
787 || linemap_macro_expansion_map_p (map_b
))
790 /* Within two different ordinary maps; they are compatible iff they
791 are in the same file. */
792 const line_map_ordinary
*ord_map_a
= linemap_check_ordinary (map_a
);
793 const line_map_ordinary
*ord_map_b
= linemap_check_ordinary (map_b
);
794 return ord_map_a
->to_file
== ord_map_b
->to_file
;
798 /* Comparator for sorting fix-it hints. */
801 fixit_cmp (const void *p_a
, const void *p_b
)
803 const fixit_hint
* hint_a
= *static_cast<const fixit_hint
* const *> (p_a
);
804 const fixit_hint
* hint_b
= *static_cast<const fixit_hint
* const *> (p_b
);
805 return hint_a
->get_start_loc () - hint_b
->get_start_loc ();
808 /* Implementation of class layout. */
810 /* Constructor for class layout.
812 Filter the ranges from the rich_location to those that we can
813 sanely print, populating m_layout_ranges and m_fixit_hints.
814 Determine the range of lines that we will print, splitting them
815 up into an ordered list of disjoint spans of contiguous line numbers.
816 Determine m_x_offset, to ensure that the primary caret
817 will fit within the max_width provided by the diagnostic_context. */
819 layout::layout (diagnostic_context
* context
,
820 rich_location
*richloc
,
821 diagnostic_t diagnostic_kind
)
822 : m_context (context
),
823 m_pp (context
->printer
),
824 m_diagnostic_kind (diagnostic_kind
),
825 m_primary_loc (richloc
->get_range (0)->m_loc
),
826 m_exploc (richloc
->get_expanded_location (0)),
827 m_colorizer (context
, diagnostic_kind
),
828 m_colorize_source_p (context
->colorize_source_p
),
829 m_layout_ranges (richloc
->get_num_locations ()),
830 m_fixit_hints (richloc
->get_num_fixit_hints ()),
831 m_line_spans (1 + richloc
->get_num_locations ()),
834 for (unsigned int idx
= 0; idx
< richloc
->get_num_locations (); idx
++)
836 /* This diagnostic printer can only cope with "sufficiently sane" ranges.
837 Ignore any ranges that are awkward to handle. */
838 const location_range
*loc_range
= richloc
->get_range (idx
);
839 maybe_add_location_range (loc_range
, false);
842 /* Populate m_fixit_hints, filtering to only those that are in the
844 for (unsigned int i
= 0; i
< richloc
->get_num_fixit_hints (); i
++)
846 const fixit_hint
*hint
= richloc
->get_fixit_hint (i
);
847 if (validate_fixit_hint_p (hint
))
848 m_fixit_hints
.safe_push (hint
);
851 /* Sort m_fixit_hints. */
852 m_fixit_hints
.qsort (fixit_cmp
);
854 /* Populate m_line_spans. */
855 calculate_line_spans ();
857 /* Adjust m_x_offset.
858 Center the primary caret to fit in max_width; all columns
859 will be adjusted accordingly. */
860 size_t max_width
= m_context
->caret_max_width
;
861 char_span line
= location_get_source_line (m_exploc
.file
, m_exploc
.line
);
862 if (line
&& (size_t)m_exploc
.column
<= line
.length ())
864 size_t right_margin
= CARET_LINE_MARGIN
;
865 size_t column
= m_exploc
.column
;
866 right_margin
= MIN (line
.length () - column
, right_margin
);
867 right_margin
= max_width
- right_margin
;
868 if (line
.length () >= max_width
&& column
> right_margin
)
869 m_x_offset
= column
- right_margin
;
870 gcc_assert (m_x_offset
>= 0);
873 if (context
->show_ruler_p
)
874 show_ruler (m_x_offset
+ max_width
);
877 /* Attempt to add LOC_RANGE to m_layout_ranges, filtering them to
878 those that we can sanely print.
880 If RESTRICT_TO_CURRENT_LINE_SPANS is true, then LOC_RANGE is also
881 filtered against this layout instance's current line spans: it
882 will only be added if the location is fully within the lines
883 already specified by other locations.
885 Return true iff LOC_RANGE was added. */
888 layout::maybe_add_location_range (const location_range
*loc_range
,
889 bool restrict_to_current_line_spans
)
891 gcc_assert (loc_range
);
893 /* Split the "range" into caret and range information. */
894 source_range src_range
= get_range_from_loc (line_table
, loc_range
->m_loc
);
896 /* Expand the various locations. */
897 expanded_location start
898 = linemap_client_expand_location_to_spelling_point
899 (src_range
.m_start
, LOCATION_ASPECT_START
);
900 expanded_location finish
901 = linemap_client_expand_location_to_spelling_point
902 (src_range
.m_finish
, LOCATION_ASPECT_FINISH
);
903 expanded_location caret
904 = linemap_client_expand_location_to_spelling_point
905 (loc_range
->m_loc
, LOCATION_ASPECT_CARET
);
907 /* If any part of the range isn't in the same file as the primary
908 location of this diagnostic, ignore the range. */
909 if (start
.file
!= m_exploc
.file
)
911 if (finish
.file
!= m_exploc
.file
)
913 if (loc_range
->m_show_caret_p
)
914 if (caret
.file
!= m_exploc
.file
)
917 /* Sanitize the caret location for non-primary ranges. */
918 if (m_layout_ranges
.length () > 0)
919 if (loc_range
->m_show_caret_p
)
920 if (!compatible_locations_p (loc_range
->m_loc
, m_primary_loc
))
921 /* Discard any non-primary ranges that can't be printed
922 sanely relative to the primary location. */
925 /* Everything is now known to be in the correct source file,
926 but it may require further sanitization. */
927 layout_range
ri (&start
, &finish
, loc_range
->m_show_caret_p
, &caret
);
929 /* If we have a range that finishes before it starts (perhaps
930 from something built via macro expansion), printing the
931 range is likely to be nonsensical. Also, attempting to do so
932 breaks assumptions within the printing code (PR c/68473).
933 Similarly, don't attempt to print ranges if one or both ends
934 of the range aren't sane to print relative to the
935 primary location (PR c++/70105). */
936 if (start
.line
> finish
.line
937 || !compatible_locations_p (src_range
.m_start
, m_primary_loc
)
938 || !compatible_locations_p (src_range
.m_finish
, m_primary_loc
))
940 /* Is this the primary location? */
941 if (m_layout_ranges
.length () == 0)
943 /* We want to print the caret for the primary location, but
944 we must sanitize away m_start and m_finish. */
945 ri
.m_start
= ri
.m_caret
;
946 ri
.m_finish
= ri
.m_caret
;
949 /* This is a non-primary range; ignore it. */
953 /* Potentially filter to just the lines already specified by other
954 locations. This is for use by gcc_rich_location::add_location_if_nearby.
955 The layout ctor doesn't use it, and can't because m_line_spans
956 hasn't been set up at that point. */
957 if (restrict_to_current_line_spans
)
959 if (!will_show_line_p (start
.line
))
961 if (!will_show_line_p (finish
.line
))
963 if (loc_range
->m_show_caret_p
)
964 if (!will_show_line_p (caret
.line
))
968 /* Passed all the tests; add the range to m_layout_ranges so that
969 it will be printed. */
970 m_layout_ranges
.safe_push (ri
);
974 /* Return true iff ROW is within one of the line spans for this layout. */
977 layout::will_show_line_p (linenum_type row
) const
979 for (int line_span_idx
= 0; line_span_idx
< get_num_line_spans ();
982 const line_span
*line_span
= get_line_span (line_span_idx
);
983 if (line_span
->contains_line_p (row
))
989 /* Return true iff we should print a heading when starting the
990 line span with the given index. */
993 layout::print_heading_for_line_span_index_p (int line_span_idx
) const
995 /* We print a heading for every change of line span, hence for every
996 line span after the initial one. */
997 if (line_span_idx
> 0)
1000 /* We also do it for the initial span if the primary location of the
1001 diagnostic is in a different span. */
1002 if (m_exploc
.line
> (int)get_line_span (0)->m_last_line
)
1008 /* Get an expanded_location for the first location of interest within
1009 the given line_span.
1010 Used when printing a heading to indicate a new line span. */
1013 layout::get_expanded_location (const line_span
*line_span
) const
1015 /* Whenever possible, use the caret location. */
1016 if (line_span
->contains_line_p (m_exploc
.line
))
1019 /* Otherwise, use the start of the first range that's present
1020 within the line_span. */
1021 for (unsigned int i
= 0; i
< m_layout_ranges
.length (); i
++)
1023 const layout_range
*lr
= &m_layout_ranges
[i
];
1024 if (line_span
->contains_line_p (lr
->m_start
.m_line
))
1026 expanded_location exploc
= m_exploc
;
1027 exploc
.line
= lr
->m_start
.m_line
;
1028 exploc
.column
= lr
->m_start
.m_column
;
1033 /* Otherwise, use the location of the first fixit-hint present within
1035 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1037 const fixit_hint
*hint
= m_fixit_hints
[i
];
1038 location_t loc
= hint
->get_start_loc ();
1039 expanded_location exploc
= expand_location (loc
);
1040 if (line_span
->contains_line_p (exploc
.line
))
1044 /* It should not be possible to have a line span that didn't
1045 contain any of the layout_range or fixit_hint instances. */
1050 /* Determine if HINT is meaningful to print within this layout. */
1053 layout::validate_fixit_hint_p (const fixit_hint
*hint
)
1055 if (LOCATION_FILE (hint
->get_start_loc ()) != m_exploc
.file
)
1057 if (LOCATION_FILE (hint
->get_next_loc ()) != m_exploc
.file
)
1063 /* Determine the range of lines affected by HINT.
1064 This assumes that HINT has already been filtered by
1065 validate_fixit_hint_p, and so affects the correct source file. */
1068 get_line_span_for_fixit_hint (const fixit_hint
*hint
)
1071 return line_span (LOCATION_LINE (hint
->get_start_loc ()),
1072 LOCATION_LINE (hint
->get_next_loc ()));
1075 /* We want to print the pertinent source code at a diagnostic. The
1076 rich_location can contain multiple locations. This will have been
1077 filtered into m_exploc (the caret for the primary location) and
1078 m_layout_ranges, for those ranges within the same source file.
1080 We will print a subset of the lines within the source file in question,
1081 as a collection of "spans" of lines.
1083 This function populates m_line_spans with an ordered, disjoint list of
1084 the line spans of interest.
1086 For example, if the primary caret location is on line 7, with ranges
1087 covering lines 5-6 and lines 9-12:
1100 then we want two spans: lines 5-7 and lines 9-12. */
1103 layout::calculate_line_spans ()
1105 /* This should only be called once, by the ctor. */
1106 gcc_assert (m_line_spans
.length () == 0);
1108 /* Populate tmp_spans with individual spans, for each of
1109 m_exploc, and for m_layout_ranges. */
1110 auto_vec
<line_span
> tmp_spans (1 + m_layout_ranges
.length ());
1111 tmp_spans
.safe_push (line_span (m_exploc
.line
, m_exploc
.line
));
1112 for (unsigned int i
= 0; i
< m_layout_ranges
.length (); i
++)
1114 const layout_range
*lr
= &m_layout_ranges
[i
];
1115 gcc_assert (lr
->m_start
.m_line
<= lr
->m_finish
.m_line
);
1116 tmp_spans
.safe_push (line_span (lr
->m_start
.m_line
,
1117 lr
->m_finish
.m_line
));
1120 /* Also add spans for any fix-it hints, in case they cover other lines. */
1121 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1123 const fixit_hint
*hint
= m_fixit_hints
[i
];
1125 tmp_spans
.safe_push (get_line_span_for_fixit_hint (hint
));
1129 tmp_spans
.qsort(line_span::comparator
);
1131 /* Now iterate through tmp_spans, copying into m_line_spans, and
1132 combining where possible. */
1133 gcc_assert (tmp_spans
.length () > 0);
1134 m_line_spans
.safe_push (tmp_spans
[0]);
1135 for (unsigned int i
= 1; i
< tmp_spans
.length (); i
++)
1137 line_span
*current
= &m_line_spans
[m_line_spans
.length () - 1];
1138 const line_span
*next
= &tmp_spans
[i
];
1139 gcc_assert (next
->m_first_line
>= current
->m_first_line
);
1140 if (next
->m_first_line
<= current
->m_last_line
+ 1)
1142 /* We can merge them. */
1143 if (next
->m_last_line
> current
->m_last_line
)
1144 current
->m_last_line
= next
->m_last_line
;
1148 /* No merger possible. */
1149 m_line_spans
.safe_push (*next
);
1153 /* Verify the result, in m_line_spans. */
1154 gcc_assert (m_line_spans
.length () > 0);
1155 for (unsigned int i
= 1; i
< m_line_spans
.length (); i
++)
1157 const line_span
*prev
= &m_line_spans
[i
- 1];
1158 const line_span
*next
= &m_line_spans
[i
];
1159 /* The individual spans must be sane. */
1160 gcc_assert (prev
->m_first_line
<= prev
->m_last_line
);
1161 gcc_assert (next
->m_first_line
<= next
->m_last_line
);
1162 /* The spans must be ordered. */
1163 gcc_assert (prev
->m_first_line
< next
->m_first_line
);
1164 /* There must be a gap of at least one line between separate spans. */
1165 gcc_assert ((prev
->m_last_line
+ 1) < next
->m_first_line
);
1169 /* Print line ROW of source code, potentially colorized at any ranges, and
1170 populate *LBOUNDS_OUT.
1171 LINE is the source line (not necessarily 0-terminated) and LINE_WIDTH
1175 layout::print_source_line (linenum_type row
, const char *line
, int line_width
,
1176 line_bounds
*lbounds_out
)
1178 m_colorizer
.set_normal_text ();
1180 /* We will stop printing the source line at any trailing
1182 line_width
= get_line_width_without_trailing_whitespace (line
,
1187 int first_non_ws
= INT_MAX
;
1188 int last_non_ws
= 0;
1190 for (column
= 1 + m_x_offset
; column
<= line_width
; column
++)
1192 /* Assuming colorization is enabled for the caret and underline
1193 characters, we may also colorize the associated characters
1194 within the source line.
1196 For frontends that generate range information, we color the
1197 associated characters in the source line the same as the
1198 carets and underlines in the annotation line, to make it easier
1199 for the reader to see the pertinent code.
1201 For frontends that only generate carets, we don't colorize the
1202 characters above them, since this would look strange (e.g.
1203 colorizing just the first character in a token). */
1204 if (m_colorize_source_p
)
1208 in_range_p
= get_state_at_point (row
, column
,
1212 m_colorizer
.set_range (state
.range_idx
);
1214 m_colorizer
.set_normal_text ();
1217 if (c
== '\0' || c
== '\t' || c
== '\r')
1221 last_non_ws
= column
;
1222 if (first_non_ws
== INT_MAX
)
1223 first_non_ws
= column
;
1225 pp_character (m_pp
, c
);
1230 lbounds_out
->m_first_non_ws
= first_non_ws
;
1231 lbounds_out
->m_last_non_ws
= last_non_ws
;
1234 /* Determine if we should print an annotation line for ROW.
1235 i.e. if any of m_layout_ranges contains ROW. */
1238 layout::should_print_annotation_line_p (linenum_type row
) const
1240 layout_range
*range
;
1242 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1243 if (range
->intersects_line_p (row
))
1248 /* Print a line consisting of the caret/underlines for the given
1252 layout::print_annotation_line (linenum_type row
, const line_bounds lbounds
)
1254 int x_bound
= get_x_bound_for_row (row
, m_exploc
.column
,
1255 lbounds
.m_last_non_ws
);
1258 for (int column
= 1 + m_x_offset
; column
< x_bound
; column
++)
1262 in_range_p
= get_state_at_point (row
, column
,
1263 lbounds
.m_first_non_ws
,
1264 lbounds
.m_last_non_ws
,
1268 /* Within a range. Draw either the caret or an underline. */
1269 m_colorizer
.set_range (state
.range_idx
);
1270 if (state
.draw_caret_p
)
1272 /* Draw the caret. */
1274 if (state
.range_idx
< rich_location::STATICALLY_ALLOCATED_RANGES
)
1275 caret_char
= m_context
->caret_chars
[state
.range_idx
];
1278 pp_character (m_pp
, caret_char
);
1281 pp_character (m_pp
, '~');
1285 /* Not in a range. */
1286 m_colorizer
.set_normal_text ();
1287 pp_character (m_pp
, ' ');
1293 /* If there are any fixit hints inserting new lines before source line ROW,
1296 They are printed on lines of their own, before the source line
1297 itself, with a leading '+'. */
1300 layout::print_leading_fixits (linenum_type row
)
1302 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1304 const fixit_hint
*hint
= m_fixit_hints
[i
];
1306 if (!hint
->ends_with_newline_p ())
1307 /* Not a newline fixit; print it in print_trailing_fixits. */
1310 gcc_assert (hint
->insertion_p ());
1312 if (hint
->affects_line_p (m_exploc
.file
, row
))
1314 /* Printing the '+' with normal colorization
1315 and the inserted line with "insert" colorization
1316 helps them stand out from each other, and from
1317 the surrounding text. */
1318 m_colorizer
.set_normal_text ();
1319 pp_character (m_pp
, '+');
1320 m_colorizer
.set_fixit_insert ();
1321 /* Print all but the trailing newline of the fix-it hint.
1322 We have to print the newline separately to avoid
1323 getting additional pp prefixes printed. */
1324 for (size_t i
= 0; i
< hint
->get_length () - 1; i
++)
1325 pp_character (m_pp
, hint
->get_string ()[i
]);
1326 m_colorizer
.set_normal_text ();
1332 /* Subroutine of layout::print_trailing_fixits.
1334 Determine if the annotation line printed for LINE contained
1335 the exact range from START_COLUMN to FINISH_COLUMN. */
1338 layout::annotation_line_showed_range_p (linenum_type line
, int start_column
,
1339 int finish_column
) const
1341 layout_range
*range
;
1343 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1344 if (range
->m_start
.m_line
== line
1345 && range
->m_start
.m_column
== start_column
1346 && range
->m_finish
.m_line
== line
1347 && range
->m_finish
.m_column
== finish_column
)
1352 /* Classes for printing trailing fix-it hints i.e. those that
1353 don't add new lines.
1355 For insertion, these can look like:
1359 For replacement, these can look like:
1361 ------------- : underline showing affected range
1364 For deletion, these can look like:
1366 ------------- : underline showing affected range
1368 This can become confusing if they overlap, and so we need
1369 to do some preprocessing to decide what to print.
1370 We use the list of fixit_hint instances affecting the line
1371 to build a list of "correction" instances, and print the
1374 For example, consider a set of fix-its for converting
1375 a C-style cast to a C++ const_cast.
1379 ..000000000111111111122222222223333333333.
1380 ..123456789012345678901234567890123456789.
1381 foo *f = (foo *)ptr->field;
1384 and the fix-it hints:
1385 - replace col 10 (the open paren) with "const_cast<"
1386 - replace col 16 (the close paren) with "> ("
1387 - insert ")" before col 27
1389 then we would get odd-looking output:
1391 foo *f = (foo *)ptr->field;
1398 It would be better to detect when fixit hints are going to
1399 overlap (those that require new lines), and to consolidate
1400 the printing of such fixits, giving something like:
1402 foo *f = (foo *)ptr->field;
1405 const_cast<foo *> (ptr->field)
1407 This works by detecting when the printing would overlap, and
1408 effectively injecting no-op replace hints into the gaps between
1409 such fix-its, so that the printing joins up.
1411 In the above example, the overlap of:
1412 - replace col 10 (the open paren) with "const_cast<"
1414 - replace col 16 (the close paren) with "> ("
1415 is fixed by injecting a no-op:
1416 - replace cols 11-15 with themselves ("foo *")
1417 and consolidating these, making:
1418 - replace cols 10-16 with "const_cast<" + "foo *" + "> ("
1420 - replace cols 10-16 with "const_cast<foo *> ("
1422 This overlaps with the final fix-it hint:
1423 - insert ")" before col 27
1424 and so we repeat the consolidation process, by injecting
1426 - replace cols 17-26 with themselves ("ptr->field")
1428 - replace cols 10-26 with "const_cast<foo *> (" + "ptr->field" + ")"
1430 - replace cols 10-26 with "const_cast<foo *> (ptr->field)"
1432 and is thus printed as desired. */
1434 /* A range of columns within a line. */
1438 column_range (int start_
, int finish_
) : start (start_
), finish (finish_
)
1440 /* We must have either a range, or an insertion. */
1441 gcc_assert (start
<= finish
|| finish
== start
- 1);
1444 bool operator== (const column_range
&other
) const
1446 return start
== other
.start
&& finish
== other
.finish
;
1453 /* Get the range of columns that HINT would affect. */
1456 get_affected_columns (const fixit_hint
*hint
)
1458 int start_column
= LOCATION_COLUMN (hint
->get_start_loc ());
1459 int finish_column
= LOCATION_COLUMN (hint
->get_next_loc ()) - 1;
1461 return column_range (start_column
, finish_column
);
1464 /* Get the range of columns that would be printed for HINT. */
1467 get_printed_columns (const fixit_hint
*hint
)
1469 int start_column
= LOCATION_COLUMN (hint
->get_start_loc ());
1470 int final_hint_column
= start_column
+ hint
->get_length () - 1;
1471 if (hint
->insertion_p ())
1473 return column_range (start_column
, final_hint_column
);
1477 int finish_column
= LOCATION_COLUMN (hint
->get_next_loc ()) - 1;
1479 return column_range (start_column
,
1480 MAX (finish_column
, final_hint_column
));
1484 /* A correction on a particular line.
1485 This describes a plan for how to print one or more fixit_hint
1486 instances that affected the line, potentially consolidating hints
1487 into corrections to make the result easier for the user to read. */
1491 correction (column_range affected_columns
,
1492 column_range printed_columns
,
1493 const char *new_text
, size_t new_text_len
)
1494 : m_affected_columns (affected_columns
),
1495 m_printed_columns (printed_columns
),
1496 m_text (xstrdup (new_text
)),
1497 m_len (new_text_len
),
1498 m_alloc_sz (new_text_len
+ 1)
1502 ~correction () { free (m_text
); }
1504 bool insertion_p () const
1506 return m_affected_columns
.start
== m_affected_columns
.finish
+ 1;
1509 void ensure_capacity (size_t len
);
1510 void ensure_terminated ();
1512 void overwrite (int dst_offset
, const char_span
&src_span
)
1514 gcc_assert (dst_offset
>= 0);
1515 gcc_assert (dst_offset
+ src_span
.length () < m_alloc_sz
);
1516 memcpy (m_text
+ dst_offset
, src_span
.get_buffer (),
1517 src_span
.length ());
1520 /* If insert, then start: the column before which the text
1521 is to be inserted, and finish is offset by the length of
1523 If replace, then the range of columns affected. */
1524 column_range m_affected_columns
;
1526 /* If insert, then start: the column before which the text
1527 is to be inserted, and finish is offset by the length of
1529 If replace, then the range of columns affected. */
1530 column_range m_printed_columns
;
1532 /* The text to be inserted/used as replacement. */
1538 /* Ensure that m_text can hold a string of length LEN
1539 (plus 1 for 0-termination). */
1542 correction::ensure_capacity (size_t len
)
1544 /* Allow 1 extra byte for 0-termination. */
1545 if (m_alloc_sz
< (len
+ 1))
1547 size_t new_alloc_sz
= (len
+ 1) * 2;
1548 m_text
= (char *)xrealloc (m_text
, new_alloc_sz
);
1549 m_alloc_sz
= new_alloc_sz
;
1553 /* Ensure that m_text is 0-terminated. */
1556 correction::ensure_terminated ()
1558 /* 0-terminate the buffer. */
1559 gcc_assert (m_len
< m_alloc_sz
);
1560 m_text
[m_len
] = '\0';
1563 /* A list of corrections affecting a particular line.
1564 This is used by layout::print_trailing_fixits for planning
1565 how to print the fix-it hints affecting the line. */
1567 struct line_corrections
1569 line_corrections (const char *filename
, linenum_type row
)
1570 : m_filename (filename
), m_row (row
)
1572 ~line_corrections ();
1574 void add_hint (const fixit_hint
*hint
);
1576 const char *m_filename
;
1578 auto_vec
<correction
*> m_corrections
;
1581 /* struct line_corrections. */
1583 line_corrections::~line_corrections ()
1587 FOR_EACH_VEC_ELT (m_corrections
, i
, c
)
1591 /* A struct wrapping a particular source line, allowing
1592 run-time bounds-checking of accesses in a checked build. */
1596 source_line (const char *filename
, int line
);
1598 char_span
as_span () { return char_span (chars
, width
); }
1604 /* source_line's ctor. */
1606 source_line::source_line (const char *filename
, int line
)
1608 char_span span
= location_get_source_line (filename
, line
);
1609 chars
= span
.get_buffer ();
1610 width
= span
.length ();
1613 /* Add HINT to the corrections for this line.
1614 Attempt to consolidate nearby hints so that they will not
1615 overlap with printed. */
1618 line_corrections::add_hint (const fixit_hint
*hint
)
1620 column_range affected_columns
= get_affected_columns (hint
);
1621 column_range printed_columns
= get_printed_columns (hint
);
1623 /* Potentially consolidate. */
1624 if (!m_corrections
.is_empty ())
1626 correction
*last_correction
1627 = m_corrections
[m_corrections
.length () - 1];
1629 /* The following consolidation code assumes that the fix-it hints
1630 have been sorted by start (done within layout's ctor). */
1631 gcc_assert (affected_columns
.start
1632 >= last_correction
->m_affected_columns
.start
);
1633 gcc_assert (printed_columns
.start
1634 >= last_correction
->m_printed_columns
.start
);
1636 if (printed_columns
.start
<= last_correction
->m_printed_columns
.finish
)
1638 /* We have two hints for which the printed forms of the hints
1639 would touch or overlap, so we need to consolidate them to avoid
1641 Attempt to inject a "replace" correction from immediately
1642 after the end of the last hint to immediately before the start
1643 of the next hint. */
1644 column_range
between (last_correction
->m_affected_columns
.finish
+ 1,
1645 printed_columns
.start
- 1);
1647 /* Try to read the source. */
1648 source_line
line (m_filename
, m_row
);
1649 if (line
.chars
&& between
.finish
< line
.width
)
1651 /* Consolidate into the last correction:
1652 add a no-op "replace" of the "between" text, and
1653 add the text from the new hint. */
1654 int old_len
= last_correction
->m_len
;
1655 gcc_assert (old_len
>= 0);
1656 int between_len
= between
.finish
+ 1 - between
.start
;
1657 gcc_assert (between_len
>= 0);
1658 int new_len
= old_len
+ between_len
+ hint
->get_length ();
1659 gcc_assert (new_len
>= 0);
1660 last_correction
->ensure_capacity (new_len
);
1661 last_correction
->overwrite
1663 line
.as_span ().subspan (between
.start
- 1,
1664 between
.finish
+ 1 - between
.start
));
1665 last_correction
->overwrite (old_len
+ between_len
,
1666 char_span (hint
->get_string (),
1667 hint
->get_length ()));
1668 last_correction
->m_len
= new_len
;
1669 last_correction
->ensure_terminated ();
1670 last_correction
->m_affected_columns
.finish
1671 = affected_columns
.finish
;
1672 last_correction
->m_printed_columns
.finish
1673 += between_len
+ hint
->get_length ();
1679 /* If no consolidation happened, add a new correction instance. */
1680 m_corrections
.safe_push (new correction (affected_columns
,
1682 hint
->get_string (),
1683 hint
->get_length ()));
1686 /* If there are any fixit hints on source line ROW, print them.
1687 They are printed in order, attempting to combine them onto lines, but
1688 starting new lines if necessary.
1689 Fix-it hints that insert new lines are handled separately,
1690 in layout::print_leading_fixits. */
1693 layout::print_trailing_fixits (linenum_type row
)
1695 /* Build a list of correction instances for the line,
1696 potentially consolidating hints (for the sake of readability). */
1697 line_corrections
corrections (m_exploc
.file
, row
);
1698 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1700 const fixit_hint
*hint
= m_fixit_hints
[i
];
1702 /* Newline fixits are handled by layout::print_leading_fixits. */
1703 if (hint
->ends_with_newline_p ())
1706 if (hint
->affects_line_p (m_exploc
.file
, row
))
1707 corrections
.add_hint (hint
);
1710 /* Now print the corrections. */
1713 int column
= m_x_offset
;
1715 FOR_EACH_VEC_ELT (corrections
.m_corrections
, i
, c
)
1717 /* For now we assume each fixit hint can only touch one line. */
1718 if (c
->insertion_p ())
1720 /* This assumes the insertion just affects one line. */
1721 int start_column
= c
->m_printed_columns
.start
;
1722 move_to_column (&column
, start_column
);
1723 m_colorizer
.set_fixit_insert ();
1724 pp_string (m_pp
, c
->m_text
);
1725 m_colorizer
.set_normal_text ();
1730 /* If the range of the replacement wasn't printed in the
1731 annotation line, then print an extra underline to
1732 indicate exactly what is being replaced.
1733 Always show it for removals. */
1734 int start_column
= c
->m_affected_columns
.start
;
1735 int finish_column
= c
->m_affected_columns
.finish
;
1736 if (!annotation_line_showed_range_p (row
, start_column
,
1740 move_to_column (&column
, start_column
);
1741 m_colorizer
.set_fixit_delete ();
1742 for (; column
<= finish_column
; column
++)
1743 pp_character (m_pp
, '-');
1744 m_colorizer
.set_normal_text ();
1746 /* Print the replacement text. REPLACE also covers
1747 removals, so only do this extra work (potentially starting
1748 a new line) if we have actual replacement text. */
1751 move_to_column (&column
, start_column
);
1752 m_colorizer
.set_fixit_insert ();
1753 pp_string (m_pp
, c
->m_text
);
1754 m_colorizer
.set_normal_text ();
1760 /* Add a trailing newline, if necessary. */
1761 move_to_column (&column
, 0);
1764 /* Disable any colorization and emit a newline. */
1767 layout::print_newline ()
1769 m_colorizer
.set_normal_text ();
1773 /* Return true if (ROW/COLUMN) is within a range of the layout.
1774 If it returns true, OUT_STATE is written to, with the
1775 range index, and whether we should draw the caret at
1776 (ROW/COLUMN) (as opposed to an underline). */
1779 layout::get_state_at_point (/* Inputs. */
1780 linenum_type row
, int column
,
1781 int first_non_ws
, int last_non_ws
,
1783 point_state
*out_state
)
1785 layout_range
*range
;
1787 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1789 if (range
->contains_point (row
, column
))
1791 out_state
->range_idx
= i
;
1793 /* Are we at the range's caret? is it visible? */
1794 out_state
->draw_caret_p
= false;
1795 if (range
->m_show_caret_p
1796 && row
== range
->m_caret
.m_line
1797 && column
== range
->m_caret
.m_column
)
1798 out_state
->draw_caret_p
= true;
1800 /* Within a multiline range, don't display any underline
1801 in any leading or trailing whitespace on a line.
1802 We do display carets, however. */
1803 if (!out_state
->draw_caret_p
)
1804 if (column
< first_non_ws
|| column
> last_non_ws
)
1807 /* We are within a range. */
1815 /* Helper function for use by layout::print_line when printing the
1816 annotation line under the source line.
1817 Get the column beyond the rightmost one that could contain a caret or
1818 range marker, given that we stop rendering at trailing whitespace.
1819 ROW is the source line within the given file.
1820 CARET_COLUMN is the column of range 0's caret.
1821 LAST_NON_WS_COLUMN is the last column containing a non-whitespace
1822 character of source (as determined when printing the source line). */
1825 layout::get_x_bound_for_row (linenum_type row
, int caret_column
,
1826 int last_non_ws_column
)
1828 int result
= caret_column
+ 1;
1830 layout_range
*range
;
1832 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1834 if (row
>= range
->m_start
.m_line
)
1836 if (range
->m_finish
.m_line
== row
)
1838 /* On the final line within a range; ensure that
1839 we render up to the end of the range. */
1840 if (result
<= range
->m_finish
.m_column
)
1841 result
= range
->m_finish
.m_column
+ 1;
1843 else if (row
< range
->m_finish
.m_line
)
1845 /* Within a multiline range; ensure that we render up to the
1846 last non-whitespace column. */
1847 if (result
<= last_non_ws_column
)
1848 result
= last_non_ws_column
+ 1;
1856 /* Given *COLUMN as an x-coordinate, print spaces to position
1857 successive output at DEST_COLUMN, printing a newline if necessary,
1858 and updating *COLUMN. */
1861 layout::move_to_column (int *column
, int dest_column
)
1863 /* Start a new line if we need to. */
1864 if (*column
> dest_column
)
1867 *column
= m_x_offset
;
1870 while (*column
< dest_column
)
1877 /* For debugging layout issues, render a ruler giving column numbers
1878 (after the 1-column indent). */
1881 layout::show_ruler (int max_column
) const
1884 if (max_column
> 99)
1887 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
1888 if (column
% 10 == 0)
1889 pp_character (m_pp
, '0' + (column
/ 100) % 10);
1897 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
1898 if (column
% 10 == 0)
1899 pp_character (m_pp
, '0' + (column
/ 10) % 10);
1906 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
1907 pp_character (m_pp
, '0' + (column
% 10));
1911 /* Print leading fix-its (for new lines inserted before the source line)
1912 then the source line, followed by an annotation line
1913 consisting of any caret/underlines, then any fixits.
1914 If the source line can't be read, print nothing. */
1916 layout::print_line (linenum_type row
)
1918 char_span line
= location_get_source_line (m_exploc
.file
, row
);
1922 line_bounds lbounds
;
1923 print_leading_fixits (row
);
1924 print_source_line (row
, line
.get_buffer (), line
.length (), &lbounds
);
1925 if (should_print_annotation_line_p (row
))
1926 print_annotation_line (row
, lbounds
);
1927 print_trailing_fixits (row
);
1930 } /* End of anonymous namespace. */
1932 /* If LOC is within the spans of lines that will already be printed for
1933 this gcc_rich_location, then add it as a secondary location and return true.
1935 Otherwise return false. */
1938 gcc_rich_location::add_location_if_nearby (location_t loc
)
1940 /* Use the layout location-handling logic to sanitize LOC,
1941 filtering it to the current line spans within a temporary
1943 layout
layout (global_dc
, this, DK_ERROR
);
1944 location_range loc_range
;
1945 loc_range
.m_loc
= loc
;
1946 loc_range
.m_show_caret_p
= false;
1947 if (!layout
.maybe_add_location_range (&loc_range
, true))
1950 add_range (loc
, false);
1954 /* Print the physical source code corresponding to the location of
1955 this diagnostic, with additional annotations. */
1958 diagnostic_show_locus (diagnostic_context
* context
,
1959 rich_location
*richloc
,
1960 diagnostic_t diagnostic_kind
)
1962 pp_newline (context
->printer
);
1964 location_t loc
= richloc
->get_loc ();
1965 /* Do nothing if source-printing has been disabled. */
1966 if (!context
->show_caret
)
1969 /* Don't attempt to print source for UNKNOWN_LOCATION and for builtins. */
1970 if (loc
<= BUILTINS_LOCATION
)
1973 /* Don't print the same source location twice in a row, unless we have
1975 if (loc
== context
->last_location
1976 && richloc
->get_num_fixit_hints () == 0)
1979 context
->last_location
= loc
;
1981 const char *saved_prefix
= pp_get_prefix (context
->printer
);
1982 pp_set_prefix (context
->printer
, NULL
);
1984 layout
layout (context
, richloc
, diagnostic_kind
);
1985 for (int line_span_idx
= 0; line_span_idx
< layout
.get_num_line_spans ();
1988 const line_span
*line_span
= layout
.get_line_span (line_span_idx
);
1989 if (layout
.print_heading_for_line_span_index_p (line_span_idx
))
1991 expanded_location exploc
= layout
.get_expanded_location (line_span
);
1992 context
->start_span (context
, exploc
);
1994 linenum_type last_line
= line_span
->get_last_line ();
1995 for (linenum_type row
= line_span
->get_first_line ();
1996 row
<= last_line
; row
++)
1997 layout
.print_line (row
);
2000 pp_set_prefix (context
->printer
, saved_prefix
);
2005 namespace selftest
{
2007 /* Selftests for diagnostic_show_locus. */
2009 /* Verify that diagnostic_show_locus works sanely on UNKNOWN_LOCATION. */
2012 test_diagnostic_show_locus_unknown_location ()
2014 test_diagnostic_context dc
;
2015 rich_location
richloc (line_table
, UNKNOWN_LOCATION
);
2016 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2017 ASSERT_STREQ ("\n", pp_formatted_text (dc
.printer
));
2020 /* Verify that diagnostic_show_locus works sanely for various
2023 All of these work on the following 1-line source file:
2026 "foo = bar.field;\n"
2027 which is set up by test_diagnostic_show_locus_one_liner and calls
2033 test_one_liner_simple_caret ()
2035 test_diagnostic_context dc
;
2036 location_t caret
= linemap_position_for_column (line_table
, 10);
2037 rich_location
richloc (line_table
, caret
);
2038 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2040 " foo = bar.field;\n"
2042 pp_formatted_text (dc
.printer
));
2045 /* Caret and range. */
2048 test_one_liner_caret_and_range ()
2050 test_diagnostic_context dc
;
2051 location_t caret
= linemap_position_for_column (line_table
, 10);
2052 location_t start
= linemap_position_for_column (line_table
, 7);
2053 location_t finish
= linemap_position_for_column (line_table
, 15);
2054 location_t loc
= make_location (caret
, start
, finish
);
2055 rich_location
richloc (line_table
, loc
);
2056 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2058 " foo = bar.field;\n"
2060 pp_formatted_text (dc
.printer
));
2063 /* Multiple ranges and carets. */
2066 test_one_liner_multiple_carets_and_ranges ()
2068 test_diagnostic_context dc
;
2070 = make_location (linemap_position_for_column (line_table
, 2),
2071 linemap_position_for_column (line_table
, 1),
2072 linemap_position_for_column (line_table
, 3));
2073 dc
.caret_chars
[0] = 'A';
2076 = make_location (linemap_position_for_column (line_table
, 8),
2077 linemap_position_for_column (line_table
, 7),
2078 linemap_position_for_column (line_table
, 9));
2079 dc
.caret_chars
[1] = 'B';
2082 = make_location (linemap_position_for_column (line_table
, 13),
2083 linemap_position_for_column (line_table
, 11),
2084 linemap_position_for_column (line_table
, 15));
2085 dc
.caret_chars
[2] = 'C';
2087 rich_location
richloc (line_table
, foo
);
2088 richloc
.add_range (bar
, true);
2089 richloc
.add_range (field
, true);
2090 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2092 " foo = bar.field;\n"
2094 pp_formatted_text (dc
.printer
));
2097 /* Insertion fix-it hint: adding an "&" to the front of "bar.field". */
2100 test_one_liner_fixit_insert_before ()
2102 test_diagnostic_context dc
;
2103 location_t caret
= linemap_position_for_column (line_table
, 7);
2104 rich_location
richloc (line_table
, caret
);
2105 richloc
.add_fixit_insert_before ("&");
2106 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2108 " foo = bar.field;\n"
2111 pp_formatted_text (dc
.printer
));
2114 /* Insertion fix-it hint: adding a "[0]" after "foo". */
2117 test_one_liner_fixit_insert_after ()
2119 test_diagnostic_context dc
;
2120 location_t start
= linemap_position_for_column (line_table
, 1);
2121 location_t finish
= linemap_position_for_column (line_table
, 3);
2122 location_t foo
= make_location (start
, start
, finish
);
2123 rich_location
richloc (line_table
, foo
);
2124 richloc
.add_fixit_insert_after ("[0]");
2125 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2127 " foo = bar.field;\n"
2130 pp_formatted_text (dc
.printer
));
2133 /* Removal fix-it hint: removal of the ".field". */
2136 test_one_liner_fixit_remove ()
2138 test_diagnostic_context dc
;
2139 location_t start
= linemap_position_for_column (line_table
, 10);
2140 location_t finish
= linemap_position_for_column (line_table
, 15);
2141 location_t dot
= make_location (start
, start
, finish
);
2142 rich_location
richloc (line_table
, dot
);
2143 richloc
.add_fixit_remove ();
2144 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2146 " foo = bar.field;\n"
2149 pp_formatted_text (dc
.printer
));
2152 /* Replace fix-it hint: replacing "field" with "m_field". */
2155 test_one_liner_fixit_replace ()
2157 test_diagnostic_context dc
;
2158 location_t start
= linemap_position_for_column (line_table
, 11);
2159 location_t finish
= linemap_position_for_column (line_table
, 15);
2160 location_t field
= make_location (start
, start
, finish
);
2161 rich_location
richloc (line_table
, field
);
2162 richloc
.add_fixit_replace ("m_field");
2163 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2165 " foo = bar.field;\n"
2168 pp_formatted_text (dc
.printer
));
2171 /* Replace fix-it hint: replacing "field" with "m_field",
2172 but where the caret was elsewhere. */
2175 test_one_liner_fixit_replace_non_equal_range ()
2177 test_diagnostic_context dc
;
2178 location_t equals
= linemap_position_for_column (line_table
, 5);
2179 location_t start
= linemap_position_for_column (line_table
, 11);
2180 location_t finish
= linemap_position_for_column (line_table
, 15);
2181 rich_location
richloc (line_table
, equals
);
2183 range
.m_start
= start
;
2184 range
.m_finish
= finish
;
2185 richloc
.add_fixit_replace (range
, "m_field");
2186 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2187 /* The replacement range is not indicated in the annotation line, so
2188 it should be indicated via an additional underline. */
2190 " foo = bar.field;\n"
2194 pp_formatted_text (dc
.printer
));
2197 /* Replace fix-it hint: replacing "field" with "m_field",
2198 where the caret was elsewhere, but where a secondary range
2199 exactly covers "field". */
2202 test_one_liner_fixit_replace_equal_secondary_range ()
2204 test_diagnostic_context dc
;
2205 location_t equals
= linemap_position_for_column (line_table
, 5);
2206 location_t start
= linemap_position_for_column (line_table
, 11);
2207 location_t finish
= linemap_position_for_column (line_table
, 15);
2208 rich_location
richloc (line_table
, equals
);
2209 location_t field
= make_location (start
, start
, finish
);
2210 richloc
.add_range (field
, false);
2211 richloc
.add_fixit_replace (field
, "m_field");
2212 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2213 /* The replacement range is indicated in the annotation line,
2214 so it shouldn't be indicated via an additional underline. */
2216 " foo = bar.field;\n"
2219 pp_formatted_text (dc
.printer
));
2222 /* Verify that we can use ad-hoc locations when adding fixits to a
2226 test_one_liner_fixit_validation_adhoc_locations ()
2228 /* Generate a range that's too long to be packed, so must
2229 be stored as an ad-hoc location (given the defaults
2230 of 5 bits or 0 bits of packed range); 41 columns > 2**5. */
2231 const location_t c7
= linemap_position_for_column (line_table
, 7);
2232 const location_t c47
= linemap_position_for_column (line_table
, 47);
2233 const location_t loc
= make_location (c7
, c7
, c47
);
2235 if (c47
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2238 ASSERT_TRUE (IS_ADHOC_LOC (loc
));
2242 rich_location
richloc (line_table
, loc
);
2243 richloc
.add_fixit_insert_before (loc
, "test");
2244 /* It should not have been discarded by the validator. */
2245 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2247 test_diagnostic_context dc
;
2248 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2250 " foo = bar.field;\n"
2253 pp_formatted_text (dc
.printer
));
2258 rich_location
richloc (line_table
, loc
);
2259 source_range range
= source_range::from_locations (loc
, c47
);
2260 richloc
.add_fixit_remove (range
);
2261 /* It should not have been discarded by the validator. */
2262 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2264 test_diagnostic_context dc
;
2265 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2267 " foo = bar.field;\n"
2269 " -----------------------------------------\n",
2270 pp_formatted_text (dc
.printer
));
2275 rich_location
richloc (line_table
, loc
);
2276 source_range range
= source_range::from_locations (loc
, c47
);
2277 richloc
.add_fixit_replace (range
, "test");
2278 /* It should not have been discarded by the validator. */
2279 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2281 test_diagnostic_context dc
;
2282 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2284 " foo = bar.field;\n"
2287 pp_formatted_text (dc
.printer
));
2291 /* Test of consolidating insertions at the same location. */
2294 test_one_liner_many_fixits_1 ()
2296 test_diagnostic_context dc
;
2297 location_t equals
= linemap_position_for_column (line_table
, 5);
2298 rich_location
richloc (line_table
, equals
);
2299 for (int i
= 0; i
< 19; i
++)
2300 richloc
.add_fixit_insert_before ("a");
2301 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2302 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2304 " foo = bar.field;\n"
2306 " aaaaaaaaaaaaaaaaaaa\n",
2307 pp_formatted_text (dc
.printer
));
2310 /* Ensure that we can add an arbitrary number of fix-it hints to a
2311 rich_location, even if they are not consolidated. */
2314 test_one_liner_many_fixits_2 ()
2316 test_diagnostic_context dc
;
2317 location_t equals
= linemap_position_for_column (line_table
, 5);
2318 rich_location
richloc (line_table
, equals
);
2319 for (int i
= 0; i
< 19; i
++)
2321 location_t loc
= linemap_position_for_column (line_table
, i
* 2);
2322 richloc
.add_fixit_insert_before (loc
, "a");
2324 ASSERT_EQ (19, richloc
.get_num_fixit_hints ());
2325 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2327 " foo = bar.field;\n"
2329 "a a a a a a a a a a a a a a a a a a a\n",
2330 pp_formatted_text (dc
.printer
));
2333 /* Run the various one-liner tests. */
2336 test_diagnostic_show_locus_one_liner (const line_table_case
&case_
)
2338 /* Create a tempfile and write some text to it.
2339 ....................0000000001111111.
2340 ....................1234567890123456. */
2341 const char *content
= "foo = bar.field;\n";
2342 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
2343 line_table_test
ltt (case_
);
2345 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 1);
2347 location_t line_end
= linemap_position_for_column (line_table
, 16);
2349 /* Don't attempt to run the tests if column data might be unavailable. */
2350 if (line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2353 ASSERT_STREQ (tmp
.get_filename (), LOCATION_FILE (line_end
));
2354 ASSERT_EQ (1, LOCATION_LINE (line_end
));
2355 ASSERT_EQ (16, LOCATION_COLUMN (line_end
));
2357 test_one_liner_simple_caret ();
2358 test_one_liner_caret_and_range ();
2359 test_one_liner_multiple_carets_and_ranges ();
2360 test_one_liner_fixit_insert_before ();
2361 test_one_liner_fixit_insert_after ();
2362 test_one_liner_fixit_remove ();
2363 test_one_liner_fixit_replace ();
2364 test_one_liner_fixit_replace_non_equal_range ();
2365 test_one_liner_fixit_replace_equal_secondary_range ();
2366 test_one_liner_fixit_validation_adhoc_locations ();
2367 test_one_liner_many_fixits_1 ();
2368 test_one_liner_many_fixits_2 ();
2371 /* Verify that gcc_rich_location::add_location_if_nearby works. */
2374 test_add_location_if_nearby (const line_table_case
&case_
)
2376 /* Create a tempfile and write some text to it.
2377 ...000000000111111111122222222223333333333.
2378 ...123456789012345678901234567890123456789. */
2380 = ("struct same_line { double x; double y; ;\n" /* line 1. */
2381 "struct different_line\n" /* line 2. */
2383 " double x;\n" /* line 4. */
2384 " double y;\n" /* line 5. */
2385 ";\n"); /* line 6. */
2386 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
2387 line_table_test
ltt (case_
);
2389 const line_map_ordinary
*ord_map
2390 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
2391 tmp
.get_filename (), 0));
2393 linemap_line_start (line_table
, 1, 100);
2395 const location_t final_line_end
2396 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 7);
2398 /* Don't attempt to run the tests if column data might be unavailable. */
2399 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2402 /* Test of add_location_if_nearby on the same line as the
2403 primary location. */
2405 const location_t missing_close_brace_1_39
2406 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 39);
2407 const location_t matching_open_brace_1_18
2408 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 18);
2409 gcc_rich_location
richloc (missing_close_brace_1_39
);
2410 bool added
= richloc
.add_location_if_nearby (matching_open_brace_1_18
);
2411 ASSERT_TRUE (added
);
2412 ASSERT_EQ (2, richloc
.get_num_locations ());
2413 test_diagnostic_context dc
;
2414 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2416 " struct same_line { double x; double y; ;\n"
2418 pp_formatted_text (dc
.printer
));
2421 /* Test of add_location_if_nearby on a different line to the
2422 primary location. */
2424 const location_t missing_close_brace_6_1
2425 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 1);
2426 const location_t matching_open_brace_3_1
2427 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 1);
2428 gcc_rich_location
richloc (missing_close_brace_6_1
);
2429 bool added
= richloc
.add_location_if_nearby (matching_open_brace_3_1
);
2430 ASSERT_FALSE (added
);
2431 ASSERT_EQ (1, richloc
.get_num_locations ());
2435 /* Verify that we print fixits even if they only affect lines
2436 outside those covered by the ranges in the rich_location. */
2439 test_diagnostic_show_locus_fixit_lines (const line_table_case
&case_
)
2441 /* Create a tempfile and write some text to it.
2442 ...000000000111111111122222222223333333333.
2443 ...123456789012345678901234567890123456789. */
2445 = ("struct point { double x; double y; };\n" /* line 1. */
2446 "struct point origin = {x: 0.0,\n" /* line 2. */
2447 " y\n" /* line 3. */
2450 " : 0.0};\n"); /* line 6. */
2451 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
2452 line_table_test
ltt (case_
);
2454 const line_map_ordinary
*ord_map
2455 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
2456 tmp
.get_filename (), 0));
2458 linemap_line_start (line_table
, 1, 100);
2460 const location_t final_line_end
2461 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 36);
2463 /* Don't attempt to run the tests if column data might be unavailable. */
2464 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2467 /* A pair of tests for modernizing the initializers to C99-style. */
2469 /* The one-liner case (line 2). */
2471 test_diagnostic_context dc
;
2473 = linemap_position_for_line_and_column (line_table
, ord_map
, 2, 24);
2474 const location_t colon
2475 = linemap_position_for_line_and_column (line_table
, ord_map
, 2, 25);
2476 rich_location
richloc (line_table
, colon
);
2477 richloc
.add_fixit_insert_before (x
, ".");
2478 richloc
.add_fixit_replace (colon
, "=");
2479 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2481 " struct point origin = {x: 0.0,\n"
2484 pp_formatted_text (dc
.printer
));
2487 /* The multiline case. The caret for the rich_location is on line 6;
2488 verify that insertion fixit on line 3 is still printed (and that
2489 span starts are printed due to the gap between the span at line 3
2490 and that at line 6). */
2492 test_diagnostic_context dc
;
2494 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 24);
2495 const location_t colon
2496 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 25);
2497 rich_location
richloc (line_table
, colon
);
2498 richloc
.add_fixit_insert_before (y
, ".");
2499 richloc
.add_fixit_replace (colon
, "=");
2500 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2509 pp_formatted_text (dc
.printer
));
2514 /* Verify that fix-it hints are appropriately consolidated.
2516 If any fix-it hints in a rich_location involve locations beyond
2517 LINE_MAP_MAX_LOCATION_WITH_COLS, then we can't reliably apply
2518 the fix-it as a whole, so there should be none.
2520 Otherwise, verify that consecutive "replace" and "remove" fix-its
2521 are merged, and that other fix-its remain separate. */
2524 test_fixit_consolidation (const line_table_case
&case_
)
2526 line_table_test
ltt (case_
);
2528 linemap_add (line_table
, LC_ENTER
, false, "test.c", 1);
2530 const location_t c10
= linemap_position_for_column (line_table
, 10);
2531 const location_t c15
= linemap_position_for_column (line_table
, 15);
2532 const location_t c16
= linemap_position_for_column (line_table
, 16);
2533 const location_t c17
= linemap_position_for_column (line_table
, 17);
2534 const location_t c20
= linemap_position_for_column (line_table
, 20);
2535 const location_t c21
= linemap_position_for_column (line_table
, 21);
2536 const location_t caret
= c10
;
2538 /* Insert + insert. */
2540 rich_location
richloc (line_table
, caret
);
2541 richloc
.add_fixit_insert_before (c10
, "foo");
2542 richloc
.add_fixit_insert_before (c15
, "bar");
2544 if (c15
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2545 /* Bogus column info for 2nd fixit, so no fixits. */
2546 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
2548 /* They should not have been merged. */
2549 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
2552 /* Insert + replace. */
2554 rich_location
richloc (line_table
, caret
);
2555 richloc
.add_fixit_insert_before (c10
, "foo");
2556 richloc
.add_fixit_replace (source_range::from_locations (c15
, c17
),
2559 if (c17
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2560 /* Bogus column info for 2nd fixit, so no fixits. */
2561 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
2563 /* They should not have been merged. */
2564 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
2567 /* Replace + non-consecutive insert. */
2569 rich_location
richloc (line_table
, caret
);
2570 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
2572 richloc
.add_fixit_insert_before (c17
, "foo");
2574 if (c17
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2575 /* Bogus column info for 2nd fixit, so no fixits. */
2576 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
2578 /* They should not have been merged. */
2579 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
2582 /* Replace + non-consecutive replace. */
2584 rich_location
richloc (line_table
, caret
);
2585 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
2587 richloc
.add_fixit_replace (source_range::from_locations (c17
, c20
),
2590 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2591 /* Bogus column info for 2nd fixit, so no fixits. */
2592 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
2594 /* They should not have been merged. */
2595 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
2598 /* Replace + consecutive replace. */
2600 rich_location
richloc (line_table
, caret
);
2601 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
2603 richloc
.add_fixit_replace (source_range::from_locations (c16
, c20
),
2606 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2607 /* Bogus column info for 2nd fixit, so no fixits. */
2608 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
2611 /* They should have been merged into a single "replace". */
2612 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2613 const fixit_hint
*hint
= richloc
.get_fixit_hint (0);
2614 ASSERT_STREQ ("foobar", hint
->get_string ());
2615 ASSERT_EQ (c10
, hint
->get_start_loc ());
2616 ASSERT_EQ (c21
, hint
->get_next_loc ());
2620 /* Replace + consecutive removal. */
2622 rich_location
richloc (line_table
, caret
);
2623 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
2625 richloc
.add_fixit_remove (source_range::from_locations (c16
, c20
));
2627 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2628 /* Bogus column info for 2nd fixit, so no fixits. */
2629 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
2632 /* They should have been merged into a single replace, with the
2633 range extended to cover that of the removal. */
2634 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2635 const fixit_hint
*hint
= richloc
.get_fixit_hint (0);
2636 ASSERT_STREQ ("foo", hint
->get_string ());
2637 ASSERT_EQ (c10
, hint
->get_start_loc ());
2638 ASSERT_EQ (c21
, hint
->get_next_loc ());
2642 /* Consecutive removals. */
2644 rich_location
richloc (line_table
, caret
);
2645 richloc
.add_fixit_remove (source_range::from_locations (c10
, c15
));
2646 richloc
.add_fixit_remove (source_range::from_locations (c16
, c20
));
2648 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2649 /* Bogus column info for 2nd fixit, so no fixits. */
2650 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
2653 /* They should have been merged into a single "replace-with-empty". */
2654 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2655 const fixit_hint
*hint
= richloc
.get_fixit_hint (0);
2656 ASSERT_STREQ ("", hint
->get_string ());
2657 ASSERT_EQ (c10
, hint
->get_start_loc ());
2658 ASSERT_EQ (c21
, hint
->get_next_loc ());
2663 /* Verify that the line_corrections machinery correctly prints
2664 overlapping fixit-hints. */
2667 test_overlapped_fixit_printing (const line_table_case
&case_
)
2669 /* Create a tempfile and write some text to it.
2670 ...000000000111111111122222222223333333333.
2671 ...123456789012345678901234567890123456789. */
2673 = (" foo *f = (foo *)ptr->field;\n");
2674 temp_source_file
tmp (SELFTEST_LOCATION
, ".C", content
);
2675 line_table_test
ltt (case_
);
2677 const line_map_ordinary
*ord_map
2678 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
2679 tmp
.get_filename (), 0));
2681 linemap_line_start (line_table
, 1, 100);
2683 const location_t final_line_end
2684 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 36);
2686 /* Don't attempt to run the tests if column data might be unavailable. */
2687 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2690 /* A test for converting a C-style cast to a C++-style cast. */
2691 const location_t open_paren
2692 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 12);
2693 const location_t close_paren
2694 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 18);
2695 const location_t expr_start
2696 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 19);
2697 const location_t expr_finish
2698 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 28);
2699 const location_t expr
= make_location (expr_start
, expr_start
, expr_finish
);
2701 /* Various examples of fix-it hints that aren't themselves consolidated,
2702 but for which the *printing* may need consolidation. */
2704 /* Example where 3 fix-it hints are printed as one. */
2706 test_diagnostic_context dc
;
2707 rich_location
richloc (line_table
, expr
);
2708 richloc
.add_fixit_replace (open_paren
, "const_cast<");
2709 richloc
.add_fixit_replace (close_paren
, "> (");
2710 richloc
.add_fixit_insert_after (")");
2712 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2714 " foo *f = (foo *)ptr->field;\n"
2716 " -----------------\n"
2717 " const_cast<foo *> (ptr->field)\n",
2718 pp_formatted_text (dc
.printer
));
2720 /* Unit-test the line_corrections machinery. */
2721 ASSERT_EQ (3, richloc
.get_num_fixit_hints ());
2722 const fixit_hint
*hint_0
= richloc
.get_fixit_hint (0);
2723 ASSERT_EQ (column_range (12, 12), get_affected_columns (hint_0
));
2724 ASSERT_EQ (column_range (12, 22), get_printed_columns (hint_0
));
2725 const fixit_hint
*hint_1
= richloc
.get_fixit_hint (1);
2726 ASSERT_EQ (column_range (18, 18), get_affected_columns (hint_1
));
2727 ASSERT_EQ (column_range (18, 20), get_printed_columns (hint_1
));
2728 const fixit_hint
*hint_2
= richloc
.get_fixit_hint (2);
2729 ASSERT_EQ (column_range (29, 28), get_affected_columns (hint_2
));
2730 ASSERT_EQ (column_range (29, 29), get_printed_columns (hint_2
));
2732 /* Add each hint in turn to a line_corrections instance,
2733 and verify that they are consolidated into one correction instance
2735 line_corrections
lc (tmp
.get_filename (), 1);
2737 /* The first replace hint by itself. */
2738 lc
.add_hint (hint_0
);
2739 ASSERT_EQ (1, lc
.m_corrections
.length ());
2740 ASSERT_EQ (column_range (12, 12), lc
.m_corrections
[0]->m_affected_columns
);
2741 ASSERT_EQ (column_range (12, 22), lc
.m_corrections
[0]->m_printed_columns
);
2742 ASSERT_STREQ ("const_cast<", lc
.m_corrections
[0]->m_text
);
2744 /* After the second replacement hint, they are printed together
2745 as a replacement (along with the text between them). */
2746 lc
.add_hint (hint_1
);
2747 ASSERT_EQ (1, lc
.m_corrections
.length ());
2748 ASSERT_STREQ ("const_cast<foo *> (", lc
.m_corrections
[0]->m_text
);
2749 ASSERT_EQ (column_range (12, 18), lc
.m_corrections
[0]->m_affected_columns
);
2750 ASSERT_EQ (column_range (12, 30), lc
.m_corrections
[0]->m_printed_columns
);
2752 /* After the final insertion hint, they are all printed together
2753 as a replacement (along with the text between them). */
2754 lc
.add_hint (hint_2
);
2755 ASSERT_STREQ ("const_cast<foo *> (ptr->field)",
2756 lc
.m_corrections
[0]->m_text
);
2757 ASSERT_EQ (1, lc
.m_corrections
.length ());
2758 ASSERT_EQ (column_range (12, 28), lc
.m_corrections
[0]->m_affected_columns
);
2759 ASSERT_EQ (column_range (12, 41), lc
.m_corrections
[0]->m_printed_columns
);
2762 /* Example where two are consolidated during printing. */
2764 test_diagnostic_context dc
;
2765 rich_location
richloc (line_table
, expr
);
2766 richloc
.add_fixit_replace (open_paren
, "CAST (");
2767 richloc
.add_fixit_replace (close_paren
, ") (");
2768 richloc
.add_fixit_insert_after (")");
2770 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2772 " foo *f = (foo *)ptr->field;\n"
2777 pp_formatted_text (dc
.printer
));
2780 /* Example where none are consolidated during printing. */
2782 test_diagnostic_context dc
;
2783 rich_location
richloc (line_table
, expr
);
2784 richloc
.add_fixit_replace (open_paren
, "CST (");
2785 richloc
.add_fixit_replace (close_paren
, ") (");
2786 richloc
.add_fixit_insert_after (")");
2788 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2790 " foo *f = (foo *)ptr->field;\n"
2795 pp_formatted_text (dc
.printer
));
2798 /* Example of deletion fix-it hints. */
2800 test_diagnostic_context dc
;
2801 rich_location
richloc (line_table
, expr
);
2802 richloc
.add_fixit_insert_before (open_paren
, "(bar *)");
2803 source_range victim
= {open_paren
, close_paren
};
2804 richloc
.add_fixit_remove (victim
);
2806 /* This case is actually handled by fixit-consolidation,
2807 rather than by line_corrections. */
2808 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
2810 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2812 " foo *f = (foo *)ptr->field;\n"
2816 pp_formatted_text (dc
.printer
));
2819 /* Example of deletion fix-it hints that would overlap. */
2821 test_diagnostic_context dc
;
2822 rich_location
richloc (line_table
, expr
);
2823 richloc
.add_fixit_insert_before (open_paren
, "(longer *)");
2824 source_range victim
= {expr_start
, expr_finish
};
2825 richloc
.add_fixit_remove (victim
);
2827 /* These fixits are not consolidated. */
2828 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
2830 /* But the corrections are. */
2831 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2833 " foo *f = (foo *)ptr->field;\n"
2835 " -----------------\n"
2836 " (longer *)(foo *)\n",
2837 pp_formatted_text (dc
.printer
));
2840 /* Example of insertion fix-it hints that would overlap. */
2842 test_diagnostic_context dc
;
2843 rich_location
richloc (line_table
, expr
);
2844 richloc
.add_fixit_insert_before (open_paren
, "LONGER THAN THE CAST");
2845 richloc
.add_fixit_insert_after (close_paren
, "TEST");
2847 /* The first insertion is long enough that if printed naively,
2848 it would overlap with the second.
2849 Verify that they are printed as a single replacement. */
2850 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2852 " foo *f = (foo *)ptr->field;\n"
2855 " LONGER THAN THE CAST(foo *)TEST\n",
2856 pp_formatted_text (dc
.printer
));
2860 /* Verify that the line_corrections machinery correctly prints
2861 overlapping fixit-hints that have been added in the wrong
2863 Adapted from PR c/81405 seen on gcc.dg/init-excess-1.c*/
2866 test_overlapped_fixit_printing_2 (const line_table_case
&case_
)
2868 /* Create a tempfile and write some text to it.
2869 ...000000000111111111122222222223333333333.
2870 ...123456789012345678901234567890123456789. */
2872 = ("int a5[][0][0] = { 1, 2 };\n");
2873 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
2874 line_table_test
ltt (case_
);
2876 const line_map_ordinary
*ord_map
2877 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
2878 tmp
.get_filename (), 0));
2880 linemap_line_start (line_table
, 1, 100);
2882 const location_t final_line_end
2883 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 100);
2885 /* Don't attempt to run the tests if column data might be unavailable. */
2886 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2889 const location_t col_1
2890 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 1);
2891 const location_t col_20
2892 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 20);
2893 const location_t col_21
2894 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 21);
2895 const location_t col_23
2896 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 23);
2897 const location_t col_25
2898 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 25);
2900 /* Two insertions, in the wrong order. */
2902 rich_location
richloc (line_table
, col_20
);
2903 richloc
.add_fixit_insert_before (col_23
, "{");
2904 richloc
.add_fixit_insert_before (col_21
, "}");
2906 /* These fixits should be accepted; they can't be consolidated. */
2907 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
2908 const fixit_hint
*hint_0
= richloc
.get_fixit_hint (0);
2909 ASSERT_EQ (column_range (23, 22), get_affected_columns (hint_0
));
2910 ASSERT_EQ (column_range (23, 23), get_printed_columns (hint_0
));
2911 const fixit_hint
*hint_1
= richloc
.get_fixit_hint (1);
2912 ASSERT_EQ (column_range (21, 20), get_affected_columns (hint_1
));
2913 ASSERT_EQ (column_range (21, 21), get_printed_columns (hint_1
));
2915 /* Verify that they're printed correctly. */
2916 test_diagnostic_context dc
;
2917 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2919 " int a5[][0][0] = { 1, 2 };\n"
2922 pp_formatted_text (dc
.printer
));
2925 /* Various overlapping insertions, some occurring "out of order"
2926 (reproducing the fix-it hints from PR c/81405). */
2928 test_diagnostic_context dc
;
2929 rich_location
richloc (line_table
, col_20
);
2931 richloc
.add_fixit_insert_before (col_20
, "{{");
2932 richloc
.add_fixit_insert_before (col_21
, "}}");
2933 richloc
.add_fixit_insert_before (col_23
, "{");
2934 richloc
.add_fixit_insert_before (col_21
, "}");
2935 richloc
.add_fixit_insert_before (col_23
, "{{");
2936 richloc
.add_fixit_insert_before (col_25
, "}");
2937 richloc
.add_fixit_insert_before (col_21
, "}");
2938 richloc
.add_fixit_insert_before (col_1
, "{");
2939 richloc
.add_fixit_insert_before (col_25
, "}");
2940 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2942 " int a5[][0][0] = { 1, 2 };\n"
2945 " {{1}}}}, {{{2 }}\n",
2946 pp_formatted_text (dc
.printer
));
2950 /* Insertion fix-it hint: adding a "break;" on a line by itself. */
2953 test_fixit_insert_containing_newline (const line_table_case
&case_
)
2955 /* Create a tempfile and write some text to it.
2956 .........................0000000001111111.
2957 .........................1234567890123456. */
2958 const char *old_content
= (" case 'a':\n" /* line 1. */
2959 " x = a;\n" /* line 2. */
2960 " case 'b':\n" /* line 3. */
2961 " x = b;\n");/* line 4. */
2963 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
2964 line_table_test
ltt (case_
);
2965 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 3);
2967 location_t case_start
= linemap_position_for_column (line_table
, 5);
2968 location_t case_finish
= linemap_position_for_column (line_table
, 13);
2969 location_t case_loc
= make_location (case_start
, case_start
, case_finish
);
2970 location_t line_start
= linemap_position_for_column (line_table
, 1);
2972 if (case_finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2975 /* Add a "break;" on a line by itself before line 3 i.e. before
2976 column 1 of line 3. */
2978 rich_location
richloc (line_table
, case_loc
);
2979 richloc
.add_fixit_insert_before (line_start
, " break;\n");
2980 test_diagnostic_context dc
;
2981 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2986 pp_formatted_text (dc
.printer
));
2989 /* Verify that attempts to add text with a newline fail when the
2990 insertion point is *not* at the start of a line. */
2992 rich_location
richloc (line_table
, case_loc
);
2993 richloc
.add_fixit_insert_before (case_start
, "break;\n");
2994 ASSERT_TRUE (richloc
.seen_impossible_fixit_p ());
2995 test_diagnostic_context dc
;
2996 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3000 pp_formatted_text (dc
.printer
));
3004 /* Insertion fix-it hint: adding a "#include <stdio.h>\n" to the top
3005 of the file, where the fix-it is printed in a different line-span
3006 to the primary range of the diagnostic. */
3009 test_fixit_insert_containing_newline_2 (const line_table_case
&case_
)
3011 /* Create a tempfile and write some text to it.
3012 .........................0000000001111111.
3013 .........................1234567890123456. */
3014 const char *old_content
= ("test (int ch)\n" /* line 1. */
3016 " putchar (ch);\n" /* line 3. */
3017 "}\n"); /* line 4. */
3019 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
3020 line_table_test
ltt (case_
);
3022 const line_map_ordinary
*ord_map
= linemap_check_ordinary
3023 (linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 0));
3024 linemap_line_start (line_table
, 1, 100);
3026 /* The primary range is the "putchar" token. */
3027 location_t putchar_start
3028 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 2);
3029 location_t putchar_finish
3030 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 8);
3031 location_t putchar_loc
3032 = make_location (putchar_start
, putchar_start
, putchar_finish
);
3033 rich_location
richloc (line_table
, putchar_loc
);
3035 /* Add a "#include <stdio.h>" on a line by itself at the top of the file. */
3036 location_t file_start
3037 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 1);
3038 richloc
.add_fixit_insert_before (file_start
, "#include <stdio.h>\n");
3040 if (putchar_finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3043 test_diagnostic_context dc
;
3044 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3047 "+#include <stdio.h>\n"
3052 pp_formatted_text (dc
.printer
));
3055 /* Replacement fix-it hint containing a newline.
3056 This will fail, as newlines are only supported when inserting at the
3057 beginning of a line. */
3060 test_fixit_replace_containing_newline (const line_table_case
&case_
)
3062 /* Create a tempfile and write some text to it.
3063 .........................0000000001111.
3064 .........................1234567890123. */
3065 const char *old_content
= "foo = bar ();\n";
3067 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
3068 line_table_test
ltt (case_
);
3069 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 1);
3071 /* Replace the " = " with "\n = ", as if we were reformatting an
3072 overly long line. */
3073 location_t start
= linemap_position_for_column (line_table
, 4);
3074 location_t finish
= linemap_position_for_column (line_table
, 6);
3075 location_t loc
= linemap_position_for_column (line_table
, 13);
3076 rich_location
richloc (line_table
, loc
);
3077 source_range range
= source_range::from_locations (start
, finish
);
3078 richloc
.add_fixit_replace (range
, "\n =");
3080 /* Arbitrary newlines are not yet supported within fix-it hints, so
3081 the fix-it should not be displayed. */
3082 ASSERT_TRUE (richloc
.seen_impossible_fixit_p ());
3084 if (finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3087 test_diagnostic_context dc
;
3088 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3092 pp_formatted_text (dc
.printer
));
3095 /* Fix-it hint, attempting to delete a newline.
3096 This will fail, as we currently only support fix-it hints that
3097 affect one line at a time. */
3100 test_fixit_deletion_affecting_newline (const line_table_case
&case_
)
3102 /* Create a tempfile and write some text to it.
3103 ..........................0000000001111.
3104 ..........................1234567890123. */
3105 const char *old_content
= ("foo = bar (\n"
3108 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
3109 line_table_test
ltt (case_
);
3110 const line_map_ordinary
*ord_map
= linemap_check_ordinary
3111 (linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 0));
3112 linemap_line_start (line_table
, 1, 100);
3114 /* Attempt to delete the " (\n...)". */
3116 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 10);
3118 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 11);
3120 = linemap_position_for_line_and_column (line_table
, ord_map
, 2, 7);
3121 location_t loc
= make_location (caret
, start
, finish
);
3122 rich_location
richloc (line_table
, loc
);
3123 richloc
. add_fixit_remove ();
3125 /* Fix-it hints that affect more than one line are not yet supported, so
3126 the fix-it should not be displayed. */
3127 ASSERT_TRUE (richloc
.seen_impossible_fixit_p ());
3129 if (finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3132 test_diagnostic_context dc
;
3133 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3139 pp_formatted_text (dc
.printer
));
3142 /* Run all of the selftests within this file. */
3145 diagnostic_show_locus_c_tests ()
3149 test_layout_range_for_single_point ();
3150 test_layout_range_for_single_line ();
3151 test_layout_range_for_multiple_lines ();
3153 test_get_line_width_without_trailing_whitespace ();
3155 test_diagnostic_show_locus_unknown_location ();
3157 for_each_line_table_case (test_diagnostic_show_locus_one_liner
);
3158 for_each_line_table_case (test_add_location_if_nearby
);
3159 for_each_line_table_case (test_diagnostic_show_locus_fixit_lines
);
3160 for_each_line_table_case (test_fixit_consolidation
);
3161 for_each_line_table_case (test_overlapped_fixit_printing
);
3162 for_each_line_table_case (test_overlapped_fixit_printing_2
);
3163 for_each_line_table_case (test_fixit_insert_containing_newline
);
3164 for_each_line_table_case (test_fixit_insert_containing_newline_2
);
3165 for_each_line_table_case (test_fixit_replace_containing_newline
);
3166 for_each_line_table_case (test_fixit_deletion_affecting_newline
);
3169 } // namespace selftest
3171 #endif /* #if CHECKING_P */