1 /* Diagnostic subroutines for printing source-code
2 Copyright (C) 1999-2016 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"
36 #ifdef GWINSZ_IN_SYS_IOCTL
37 # include <sys/ioctl.h>
40 /* Classes for rendering source code and diagnostics, within an
42 The work is done by "class layout", which embeds and uses
43 "class colorizer" and "class layout_range" to get things done. */
47 /* The state at a given point of the source code, assuming that we're
48 in a range: which range are we in, and whether we should draw a caret at
57 /* A class to inject colorization codes when printing the diagnostic locus.
59 It has one kind of colorization for each of:
61 - range 0 (the "primary location")
65 The class caches the lookup of the color codes for the above.
67 The class also has responsibility for tracking which of the above is
68 active, filtering out unnecessary changes. This allows
69 layout::print_source_line and layout::print_annotation_line
70 to simply request a colorization code for *every* character they print,
71 via this class, and have the filtering be done for them here. */
76 colorizer (diagnostic_context
*context
,
77 diagnostic_t diagnostic_kind
);
80 void set_range (int range_idx
) { set_state (range_idx
); }
81 void set_normal_text () { set_state (STATE_NORMAL_TEXT
); }
82 void set_fixit_hint () { set_state (0); }
85 void set_state (int state
);
86 void begin_state (int state
);
87 void finish_state (int state
);
90 static const int STATE_NORMAL_TEXT
= -1;
92 diagnostic_context
*m_context
;
93 diagnostic_t m_diagnostic_kind
;
95 const char *m_caret_cs
;
96 const char *m_caret_ce
;
97 const char *m_range1_cs
;
98 const char *m_range2_cs
;
99 const char *m_range_ce
;
102 /* A point within a layout_range; similar to an expanded_location,
103 but after filtering on file. */
108 layout_point (const expanded_location
&exploc
)
109 : m_line (exploc
.line
),
110 m_column (exploc
.column
) {}
116 /* A class for use by "class layout" below: a filtered location_range. */
121 layout_range (const expanded_location
*start_exploc
,
122 const expanded_location
*finish_exploc
,
124 const expanded_location
*caret_exploc
);
126 bool contains_point (int row
, int column
) const;
128 layout_point m_start
;
129 layout_point m_finish
;
131 layout_point m_caret
;
134 /* A struct for use by layout::print_source_line for telling
135 layout::print_annotation_line the extents of the source line that
136 it printed, so that underlines can be clipped appropriately. */
144 /* A range of contiguous source lines within a layout (e.g. "lines 5-10"
145 or "line 23"). During the layout ctor, layout::calculate_line_spans
146 splits the pertinent source lines into a list of disjoint line_span
147 instances (e.g. lines 5-10, lines 15-20, line 23). */
151 line_span (linenum_type first_line
, linenum_type last_line
)
152 : m_first_line (first_line
), m_last_line (last_line
)
154 gcc_assert (first_line
<= last_line
);
156 linenum_type
get_first_line () const { return m_first_line
; }
157 linenum_type
get_last_line () const { return m_last_line
; }
159 bool contains_line_p (linenum_type line
) const
161 return line
>= m_first_line
&& line
<= m_last_line
;
164 static int comparator (const void *p1
, const void *p2
)
166 const line_span
*ls1
= (const line_span
*)p1
;
167 const line_span
*ls2
= (const line_span
*)p2
;
168 int first_line_diff
= (int)ls1
->m_first_line
- (int)ls2
->m_first_line
;
170 return first_line_diff
;
171 return (int)ls1
->m_last_line
- (int)ls2
->m_last_line
;
174 linenum_type m_first_line
;
175 linenum_type m_last_line
;
178 /* A class to control the overall layout when printing a diagnostic.
180 The layout is determined within the constructor.
181 It is then printed by repeatedly calling the "print_source_line",
182 "print_annotation_line" and "print_any_fixits" methods.
184 We assume we have disjoint ranges. */
189 layout (diagnostic_context
*context
,
190 rich_location
*richloc
,
191 diagnostic_t diagnostic_kind
);
193 int get_num_line_spans () const { return m_line_spans
.length (); }
194 const line_span
*get_line_span (int idx
) const { return &m_line_spans
[idx
]; }
196 bool print_heading_for_line_span_index_p (int line_span_idx
) const;
198 expanded_location
get_expanded_location (const line_span
*) const;
200 bool print_source_line (int row
, line_bounds
*lbounds_out
);
201 void print_annotation_line (int row
, const line_bounds lbounds
);
202 void print_any_fixits (int row
, const rich_location
*richloc
);
204 void show_ruler (int max_column
) const;
207 void calculate_line_spans ();
209 void print_newline ();
212 get_state_at_point (/* Inputs. */
214 int first_non_ws
, int last_non_ws
,
216 point_state
*out_state
);
219 get_x_bound_for_row (int row
, int caret_column
,
223 move_to_column (int *column
, int dest_column
);
226 diagnostic_context
*m_context
;
227 pretty_printer
*m_pp
;
228 diagnostic_t m_diagnostic_kind
;
229 expanded_location m_exploc
;
230 colorizer m_colorizer
;
231 bool m_colorize_source_p
;
232 auto_vec
<layout_range
> m_layout_ranges
;
233 auto_vec
<line_span
> m_line_spans
;
237 /* Implementation of "class colorizer". */
239 /* The constructor for "colorizer". Lookup and store color codes for the
240 different kinds of things we might need to print. */
242 colorizer::colorizer (diagnostic_context
*context
,
243 diagnostic_t diagnostic_kind
) :
245 m_diagnostic_kind (diagnostic_kind
),
246 m_current_state (STATE_NORMAL_TEXT
)
248 m_caret_ce
= colorize_stop (pp_show_color (context
->printer
));
249 m_range1_cs
= colorize_start (pp_show_color (context
->printer
), "range1");
250 m_range2_cs
= colorize_start (pp_show_color (context
->printer
), "range2");
251 m_range_ce
= colorize_stop (pp_show_color (context
->printer
));
254 /* The destructor for "colorize". If colorization is on, print a code to
257 colorizer::~colorizer ()
259 finish_state (m_current_state
);
262 /* Update state, printing color codes if necessary if there's a state
266 colorizer::set_state (int new_state
)
268 if (m_current_state
!= new_state
)
270 finish_state (m_current_state
);
271 m_current_state
= new_state
;
272 begin_state (new_state
);
276 /* Turn on any colorization for STATE. */
279 colorizer::begin_state (int state
)
283 case STATE_NORMAL_TEXT
:
287 /* Make range 0 be the same color as the "kind" text
288 (error vs warning vs note). */
291 colorize_start (pp_show_color (m_context
->printer
),
292 diagnostic_get_color_for_kind (m_diagnostic_kind
)));
296 pp_string (m_context
->printer
, m_range1_cs
);
300 pp_string (m_context
->printer
, m_range2_cs
);
304 /* We don't expect more than 3 ranges per diagnostic. */
310 /* Turn off any colorization for STATE. */
313 colorizer::finish_state (int state
)
317 case STATE_NORMAL_TEXT
:
321 pp_string (m_context
->printer
, m_caret_ce
);
325 /* Within a range. */
326 gcc_assert (state
> 0);
327 pp_string (m_context
->printer
, m_range_ce
);
332 /* Implementation of class layout_range. */
334 /* The constructor for class layout_range.
335 Initialize various layout_point fields from expanded_location
336 equivalents; we've already filtered on file. */
338 layout_range::layout_range (const expanded_location
*start_exploc
,
339 const expanded_location
*finish_exploc
,
341 const expanded_location
*caret_exploc
)
342 : m_start (*start_exploc
),
343 m_finish (*finish_exploc
),
344 m_show_caret_p (show_caret_p
),
345 m_caret (*caret_exploc
)
349 /* Is (column, row) within the given range?
350 We've already filtered on the file.
352 Ranges are closed (both limits are within the range).
354 Example A: a single-line range:
355 start: (col=22, line=2)
356 finish: (col=38, line=2)
358 |00000011111111112222222222333333333344444444444
359 |34567890123456789012345678901234567890123456789
360 --+-----------------------------------------------
361 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
362 02|bbbbbbbbbbbbbbbbbbbSwwwwwwwwwwwwwwwFaaaaaaaaaaa
363 03|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
365 Example B: a multiline range with
366 start: (col=14, line=3)
367 finish: (col=08, line=5)
369 |00000011111111112222222222333333333344444444444
370 |34567890123456789012345678901234567890123456789
371 --+-----------------------------------------------
372 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
373 02|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
374 03|bbbbbbbbbbbSwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
375 04|wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
376 05|wwwwwFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
377 06|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
378 --+-----------------------------------------------
381 - 'b' indicates a point *before* the range
382 - 'S' indicates the start of the range
383 - 'w' indicates a point within the range
384 - 'F' indicates the finish of the range (which is
386 - 'a' indicates a subsequent point *after* the range. */
389 layout_range::contains_point (int row
, int column
) const
391 gcc_assert (m_start
.m_line
<= m_finish
.m_line
);
392 /* ...but the equivalent isn't true for the columns;
393 consider example B in the comment above. */
395 if (row
< m_start
.m_line
)
396 /* Points before the first line of the range are
397 outside it (corresponding to line 01 in example A
398 and lines 01 and 02 in example B above). */
401 if (row
== m_start
.m_line
)
402 /* On same line as start of range (corresponding
403 to line 02 in example A and line 03 in example B). */
405 if (column
< m_start
.m_column
)
406 /* Points on the starting line of the range, but
407 before the column in which it begins. */
410 if (row
< m_finish
.m_line
)
411 /* This is a multiline range; the point
412 is within it (corresponds to line 03 in example B
413 from column 14 onwards) */
417 /* This is a single-line range. */
418 gcc_assert (row
== m_finish
.m_line
);
419 return column
<= m_finish
.m_column
;
423 /* The point is in a line beyond that containing the
424 start of the range: lines 03 onwards in example A,
425 and lines 04 onwards in example B. */
426 gcc_assert (row
> m_start
.m_line
);
428 if (row
> m_finish
.m_line
)
429 /* The point is beyond the final line of the range
430 (lines 03 onwards in example A, and lines 06 onwards
434 if (row
< m_finish
.m_line
)
436 /* The point is in a line that's fully within a multiline
437 range (e.g. line 04 in example B). */
438 gcc_assert (m_start
.m_line
< m_finish
.m_line
);
442 gcc_assert (row
== m_finish
.m_line
);
444 return column
<= m_finish
.m_column
;
449 /* A helper function for testing layout_range::contains_point. */
452 make_range (int start_line
, int start_col
, int end_line
, int end_col
)
454 const expanded_location start_exploc
455 = {"test.c", start_line
, start_col
, NULL
, false};
456 const expanded_location finish_exploc
457 = {"test.c", end_line
, end_col
, NULL
, false};
458 return layout_range (&start_exploc
, &finish_exploc
, false,
462 /* Selftests for layout_range::contains_point. */
464 /* Selftest for layout_range::contains_point where the layout_range
465 is a range with start==end i.e. a single point. */
468 test_range_contains_point_for_single_point ()
470 layout_range point
= make_range (7, 10, 7, 10);
472 /* Before the line. */
473 ASSERT_FALSE (point
.contains_point (6, 1));
475 /* On the line, but before start. */
476 ASSERT_FALSE (point
.contains_point (7, 9));
479 ASSERT_TRUE (point
.contains_point (7, 10));
481 /* On the line, after the point. */
482 ASSERT_FALSE (point
.contains_point (7, 11));
484 /* After the line. */
485 ASSERT_FALSE (point
.contains_point (8, 1));
488 /* Selftest for layout_range::contains_point where the layout_range
489 is the single-line range shown as "Example A" above. */
492 test_range_contains_point_for_single_line ()
494 layout_range example_a
= make_range (2, 22, 2, 38);
496 /* Before the line. */
497 ASSERT_FALSE (example_a
.contains_point (1, 1));
499 /* On the line, but before start. */
500 ASSERT_FALSE (example_a
.contains_point (2, 21));
502 /* On the line, at the start. */
503 ASSERT_TRUE (example_a
.contains_point (2, 22));
505 /* On the line, within the range. */
506 ASSERT_TRUE (example_a
.contains_point (2, 23));
508 /* On the line, at the end. */
509 ASSERT_TRUE (example_a
.contains_point (2, 38));
511 /* On the line, after the end. */
512 ASSERT_FALSE (example_a
.contains_point (2, 39));
514 /* After the line. */
515 ASSERT_FALSE (example_a
.contains_point (2, 39));
518 /* Selftest for layout_range::contains_point where the layout_range
519 is the multi-line range shown as "Example B" above. */
522 test_range_contains_point_for_multiple_lines ()
524 layout_range example_b
= make_range (3, 14, 5, 8);
526 /* Before first line. */
527 ASSERT_FALSE (example_b
.contains_point (1, 1));
529 /* On the first line, but before start. */
530 ASSERT_FALSE (example_b
.contains_point (3, 13));
533 ASSERT_TRUE (example_b
.contains_point (3, 14));
535 /* On the first line, within the range. */
536 ASSERT_TRUE (example_b
.contains_point (3, 15));
538 /* On an interior line.
539 The column number should not matter; try various boundary
541 ASSERT_TRUE (example_b
.contains_point (4, 1));
542 ASSERT_TRUE (example_b
.contains_point (4, 7));
543 ASSERT_TRUE (example_b
.contains_point (4, 8));
544 ASSERT_TRUE (example_b
.contains_point (4, 9));
545 ASSERT_TRUE (example_b
.contains_point (4, 13));
546 ASSERT_TRUE (example_b
.contains_point (4, 14));
547 ASSERT_TRUE (example_b
.contains_point (4, 15));
549 /* On the final line, before the end. */
550 ASSERT_TRUE (example_b
.contains_point (5, 7));
552 /* On the final line, at the end. */
553 ASSERT_TRUE (example_b
.contains_point (5, 8));
555 /* On the final line, after the end. */
556 ASSERT_FALSE (example_b
.contains_point (5, 9));
558 /* After the line. */
559 ASSERT_FALSE (example_b
.contains_point (6, 1));
562 #endif /* #if CHECKING_P */
564 /* Given a source line LINE of length LINE_WIDTH, determine the width
565 without any trailing whitespace. */
568 get_line_width_without_trailing_whitespace (const char *line
, int line_width
)
570 int result
= line_width
;
573 char ch
= line
[result
- 1];
574 if (ch
== ' ' || ch
== '\t')
579 gcc_assert (result
>= 0);
580 gcc_assert (result
<= line_width
);
581 gcc_assert (result
== 0 ||
582 (line
[result
- 1] != ' '
583 && line
[result
-1] != '\t'));
589 /* A helper function for testing get_line_width_without_trailing_whitespace. */
592 assert_eq (const char *line
, int expected_width
)
595 = get_line_width_without_trailing_whitespace (line
, strlen (line
));
596 ASSERT_EQ (actual_value
, expected_width
);
599 /* Verify that get_line_width_without_trailing_whitespace is sane for
600 various inputs. It is not required to handle newlines. */
603 test_get_line_width_without_trailing_whitespace ()
608 assert_eq ("hello world", 11);
609 assert_eq ("hello world ", 11);
610 assert_eq ("hello world \t\t ", 11);
613 #endif /* #if CHECKING_P */
615 /* Helper function for layout's ctor, for sanitizing locations relative
616 to the primary location within a diagnostic.
618 Compare LOC_A and LOC_B to see if it makes sense to print underlines
619 connecting their expanded locations. Doing so is only guaranteed to
620 make sense if the locations share the same macro expansion "history"
621 i.e. they can be traced through the same macro expansions, eventually
622 reaching an ordinary map.
624 This may be too strong a condition, but it effectively sanitizes
625 PR c++/70105, which has an example of printing an expression where the
626 final location of the expression is in a different macro, which
627 erroneously was leading to hundreds of lines of irrelevant source
631 compatible_locations_p (location_t loc_a
, location_t loc_b
)
633 if (IS_ADHOC_LOC (loc_a
))
634 loc_a
= get_location_from_adhoc_loc (line_table
, loc_a
);
635 if (IS_ADHOC_LOC (loc_b
))
636 loc_b
= get_location_from_adhoc_loc (line_table
, loc_b
);
638 /* If either location is one of the special locations outside of a
639 linemap, they are only compatible if they are equal. */
640 if (loc_a
< RESERVED_LOCATION_COUNT
641 || loc_b
< RESERVED_LOCATION_COUNT
)
642 return loc_a
== loc_b
;
644 const line_map
*map_a
= linemap_lookup (line_table
, loc_a
);
645 linemap_assert (map_a
);
647 const line_map
*map_b
= linemap_lookup (line_table
, loc_b
);
648 linemap_assert (map_b
);
650 /* Are they within the same map? */
653 /* Are both within the same macro expansion? */
654 if (linemap_macro_expansion_map_p (map_a
))
656 /* Expand each location towards the spelling location, and
658 const line_map_macro
*macro_map
= linemap_check_macro (map_a
);
659 source_location loc_a_toward_spelling
660 = linemap_macro_map_loc_unwind_toward_spelling (line_table
,
663 source_location loc_b_toward_spelling
664 = linemap_macro_map_loc_unwind_toward_spelling (line_table
,
667 return compatible_locations_p (loc_a_toward_spelling
,
668 loc_b_toward_spelling
);
671 /* Otherwise they are within the same ordinary map. */
676 /* Within different maps. */
678 /* If either is within a macro expansion, they are incompatible. */
679 if (linemap_macro_expansion_map_p (map_a
)
680 || linemap_macro_expansion_map_p (map_b
))
683 /* Within two different ordinary maps; they are compatible iff they
684 are in the same file. */
685 const line_map_ordinary
*ord_map_a
= linemap_check_ordinary (map_a
);
686 const line_map_ordinary
*ord_map_b
= linemap_check_ordinary (map_b
);
687 return ord_map_a
->to_file
== ord_map_b
->to_file
;
691 /* Implementation of class layout. */
693 /* Constructor for class layout.
695 Filter the ranges from the rich_location to those that we can
696 sanely print, populating m_layout_ranges.
697 Determine the range of lines that we will print, splitting them
698 up into an ordered list of disjoint spans of contiguous line numbers.
699 Determine m_x_offset, to ensure that the primary caret
700 will fit within the max_width provided by the diagnostic_context. */
702 layout::layout (diagnostic_context
* context
,
703 rich_location
*richloc
,
704 diagnostic_t diagnostic_kind
)
705 : m_context (context
),
706 m_pp (context
->printer
),
707 m_diagnostic_kind (diagnostic_kind
),
708 m_exploc (richloc
->get_expanded_location (0)),
709 m_colorizer (context
, diagnostic_kind
),
710 m_colorize_source_p (context
->colorize_source_p
),
711 m_layout_ranges (rich_location::MAX_RANGES
),
712 m_line_spans (1 + rich_location::MAX_RANGES
),
715 source_location primary_loc
= richloc
->get_range (0)->m_loc
;
717 for (unsigned int idx
= 0; idx
< richloc
->get_num_locations (); idx
++)
719 /* This diagnostic printer can only cope with "sufficiently sane" ranges.
720 Ignore any ranges that are awkward to handle. */
721 const location_range
*loc_range
= richloc
->get_range (idx
);
723 /* Split the "range" into caret and range information. */
724 source_range src_range
= get_range_from_loc (line_table
, loc_range
->m_loc
);
726 /* Expand the various locations. */
727 expanded_location start
728 = linemap_client_expand_location_to_spelling_point (src_range
.m_start
);
729 expanded_location finish
730 = linemap_client_expand_location_to_spelling_point (src_range
.m_finish
);
731 expanded_location caret
732 = linemap_client_expand_location_to_spelling_point (loc_range
->m_loc
);
734 /* If any part of the range isn't in the same file as the primary
735 location of this diagnostic, ignore the range. */
736 if (start
.file
!= m_exploc
.file
)
738 if (finish
.file
!= m_exploc
.file
)
740 if (loc_range
->m_show_caret_p
)
741 if (caret
.file
!= m_exploc
.file
)
744 /* Sanitize the caret location for non-primary ranges. */
745 if (m_layout_ranges
.length () > 0)
746 if (loc_range
->m_show_caret_p
)
747 if (!compatible_locations_p (loc_range
->m_loc
, primary_loc
))
748 /* Discard any non-primary ranges that can't be printed
749 sanely relative to the primary location. */
752 /* Everything is now known to be in the correct source file,
753 but it may require further sanitization. */
754 layout_range
ri (&start
, &finish
, loc_range
->m_show_caret_p
, &caret
);
756 /* If we have a range that finishes before it starts (perhaps
757 from something built via macro expansion), printing the
758 range is likely to be nonsensical. Also, attempting to do so
759 breaks assumptions within the printing code (PR c/68473).
760 Similarly, don't attempt to print ranges if one or both ends
761 of the range aren't sane to print relative to the
762 primary location (PR c++/70105). */
763 if (start
.line
> finish
.line
764 || !compatible_locations_p (src_range
.m_start
, primary_loc
)
765 || !compatible_locations_p (src_range
.m_finish
, primary_loc
))
767 /* Is this the primary location? */
768 if (m_layout_ranges
.length () == 0)
770 /* We want to print the caret for the primary location, but
771 we must sanitize away m_start and m_finish. */
772 ri
.m_start
= ri
.m_caret
;
773 ri
.m_finish
= ri
.m_caret
;
776 /* This is a non-primary range; ignore it. */
780 /* Passed all the tests; add the range to m_layout_ranges so that
781 it will be printed. */
782 m_layout_ranges
.safe_push (ri
);
785 /* Populate m_line_spans. */
786 calculate_line_spans ();
788 /* Adjust m_x_offset.
789 Center the primary caret to fit in max_width; all columns
790 will be adjusted accordingly. */
791 int max_width
= m_context
->caret_max_width
;
793 const char *line
= location_get_source_line (m_exploc
.file
, m_exploc
.line
,
795 if (line
&& m_exploc
.column
<= line_width
)
797 int right_margin
= CARET_LINE_MARGIN
;
798 int column
= m_exploc
.column
;
799 right_margin
= MIN (line_width
- column
, right_margin
);
800 right_margin
= max_width
- right_margin
;
801 if (line_width
>= max_width
&& column
> right_margin
)
802 m_x_offset
= column
- right_margin
;
803 gcc_assert (m_x_offset
>= 0);
806 if (context
->show_ruler_p
)
807 show_ruler (m_x_offset
+ max_width
);
810 /* Return true iff we should print a heading when starting the
811 line span with the given index. */
814 layout::print_heading_for_line_span_index_p (int line_span_idx
) const
816 /* We print a heading for every change of line span, hence for every
817 line span after the initial one. */
818 if (line_span_idx
> 0)
821 /* We also do it for the initial span if the primary location of the
822 diagnostic is in a different span. */
823 if (m_exploc
.line
> (int)get_line_span (0)->m_last_line
)
829 /* Get an expanded_location for the first location of interest within
831 Used when printing a heading to indicate a new line span. */
834 layout::get_expanded_location (const line_span
*line_span
) const
836 /* Whenever possible, use the caret location. */
837 if (line_span
->contains_line_p (m_exploc
.line
))
840 /* Otherwise, use the start of the first range that's present
841 within the line_span. */
842 for (unsigned int i
= 0; i
< m_layout_ranges
.length (); i
++)
844 const layout_range
*lr
= &m_layout_ranges
[i
];
845 if (line_span
->contains_line_p (lr
->m_start
.m_line
))
847 expanded_location exploc
= m_exploc
;
848 exploc
.line
= lr
->m_start
.m_line
;
849 exploc
.column
= lr
->m_start
.m_column
;
854 /* It should not be possible to have a line span that didn't
855 contain any of the layout_range instances. */
860 /* We want to print the pertinent source code at a diagnostic. The
861 rich_location can contain multiple locations. This will have been
862 filtered into m_exploc (the caret for the primary location) and
863 m_layout_ranges, for those ranges within the same source file.
865 We will print a subset of the lines within the source file in question,
866 as a collection of "spans" of lines.
868 This function populates m_line_spans with an ordered, disjoint list of
869 the line spans of interest.
871 For example, if the primary caret location is on line 7, with ranges
872 covering lines 5-6 and lines 9-12:
885 then we want two spans: lines 5-7 and lines 9-12. */
888 layout::calculate_line_spans ()
890 /* This should only be called once, by the ctor. */
891 gcc_assert (m_line_spans
.length () == 0);
893 /* Populate tmp_spans with individual spans, for each of
894 m_exploc, and for m_layout_ranges. */
895 auto_vec
<line_span
> tmp_spans (1 + rich_location::MAX_RANGES
);
896 tmp_spans
.safe_push (line_span (m_exploc
.line
, m_exploc
.line
));
897 for (unsigned int i
= 0; i
< m_layout_ranges
.length (); i
++)
899 const layout_range
*lr
= &m_layout_ranges
[i
];
900 gcc_assert (lr
->m_start
.m_line
<= lr
->m_finish
.m_line
);
901 tmp_spans
.safe_push (line_span (lr
->m_start
.m_line
,
902 lr
->m_finish
.m_line
));
906 tmp_spans
.qsort(line_span::comparator
);
908 /* Now iterate through tmp_spans, copying into m_line_spans, and
909 combining where possible. */
910 gcc_assert (tmp_spans
.length () > 0);
911 m_line_spans
.safe_push (tmp_spans
[0]);
912 for (unsigned int i
= 1; i
< tmp_spans
.length (); i
++)
914 line_span
*current
= &m_line_spans
[m_line_spans
.length () - 1];
915 const line_span
*next
= &tmp_spans
[i
];
916 gcc_assert (next
->m_first_line
>= current
->m_first_line
);
917 if (next
->m_first_line
<= current
->m_last_line
+ 1)
919 /* We can merge them. */
920 if (next
->m_last_line
> current
->m_last_line
)
921 current
->m_last_line
= next
->m_last_line
;
925 /* No merger possible. */
926 m_line_spans
.safe_push (*next
);
930 /* Verify the result, in m_line_spans. */
931 gcc_assert (m_line_spans
.length () > 0);
932 for (unsigned int i
= 1; i
< m_line_spans
.length (); i
++)
934 const line_span
*prev
= &m_line_spans
[i
- 1];
935 const line_span
*next
= &m_line_spans
[i
];
936 /* The individual spans must be sane. */
937 gcc_assert (prev
->m_first_line
<= prev
->m_last_line
);
938 gcc_assert (next
->m_first_line
<= next
->m_last_line
);
939 /* The spans must be ordered. */
940 gcc_assert (prev
->m_first_line
< next
->m_first_line
);
941 /* There must be a gap of at least one line between separate spans. */
942 gcc_assert ((prev
->m_last_line
+ 1) < next
->m_first_line
);
946 /* Attempt to print line ROW of source code, potentially colorized at any
948 Return true if the line was printed, populating *LBOUNDS_OUT.
949 Return false if the source line could not be read, leaving *LBOUNDS_OUT
953 layout::print_source_line (int row
, line_bounds
*lbounds_out
)
956 const char *line
= location_get_source_line (m_exploc
.file
, row
,
961 m_colorizer
.set_normal_text ();
963 /* We will stop printing the source line at any trailing
965 line_width
= get_line_width_without_trailing_whitespace (line
,
970 int first_non_ws
= INT_MAX
;
973 for (column
= 1 + m_x_offset
; column
<= line_width
; column
++)
975 /* Assuming colorization is enabled for the caret and underline
976 characters, we may also colorize the associated characters
977 within the source line.
979 For frontends that generate range information, we color the
980 associated characters in the source line the same as the
981 carets and underlines in the annotation line, to make it easier
982 for the reader to see the pertinent code.
984 For frontends that only generate carets, we don't colorize the
985 characters above them, since this would look strange (e.g.
986 colorizing just the first character in a token). */
987 if (m_colorize_source_p
)
991 in_range_p
= get_state_at_point (row
, column
,
995 m_colorizer
.set_range (state
.range_idx
);
997 m_colorizer
.set_normal_text ();
999 char c
= *line
== '\t' ? ' ' : *line
;
1004 last_non_ws
= column
;
1005 if (first_non_ws
== INT_MAX
)
1006 first_non_ws
= column
;
1008 pp_character (m_pp
, c
);
1013 lbounds_out
->m_first_non_ws
= first_non_ws
;
1014 lbounds_out
->m_last_non_ws
= last_non_ws
;
1018 /* Print a line consisting of the caret/underlines for the given
1022 layout::print_annotation_line (int row
, const line_bounds lbounds
)
1024 int x_bound
= get_x_bound_for_row (row
, m_exploc
.column
,
1025 lbounds
.m_last_non_ws
);
1028 for (int column
= 1 + m_x_offset
; column
< x_bound
; column
++)
1032 in_range_p
= get_state_at_point (row
, column
,
1033 lbounds
.m_first_non_ws
,
1034 lbounds
.m_last_non_ws
,
1038 /* Within a range. Draw either the caret or an underline. */
1039 m_colorizer
.set_range (state
.range_idx
);
1040 if (state
.draw_caret_p
)
1041 /* Draw the caret. */
1042 pp_character (m_pp
, m_context
->caret_chars
[state
.range_idx
]);
1044 pp_character (m_pp
, '~');
1048 /* Not in a range. */
1049 m_colorizer
.set_normal_text ();
1050 pp_character (m_pp
, ' ');
1056 /* If there are any fixit hints on source line ROW within RICHLOC, print them.
1057 They are printed in order, attempting to combine them onto lines, but
1058 starting new lines if necessary. */
1061 layout::print_any_fixits (int row
, const rich_location
*richloc
)
1064 for (unsigned int i
= 0; i
< richloc
->get_num_fixit_hints (); i
++)
1066 fixit_hint
*hint
= richloc
->get_fixit_hint (i
);
1067 if (hint
->affects_line_p (m_exploc
.file
, row
))
1069 /* For now we assume each fixit hint can only touch one line. */
1070 switch (hint
->get_kind ())
1072 case fixit_hint::INSERT
:
1074 fixit_insert
*insert
= static_cast <fixit_insert
*> (hint
);
1075 /* This assumes the insertion just affects one line. */
1077 = LOCATION_COLUMN (insert
->get_location ());
1078 move_to_column (&column
, start_column
);
1079 m_colorizer
.set_fixit_hint ();
1080 pp_string (m_pp
, insert
->get_string ());
1081 m_colorizer
.set_normal_text ();
1082 column
+= insert
->get_length ();
1086 case fixit_hint::REMOVE
:
1088 fixit_remove
*remove
= static_cast <fixit_remove
*> (hint
);
1089 /* This assumes the removal just affects one line. */
1090 source_range src_range
= remove
->get_range ();
1091 int start_column
= LOCATION_COLUMN (src_range
.m_start
);
1092 int finish_column
= LOCATION_COLUMN (src_range
.m_finish
);
1093 move_to_column (&column
, start_column
);
1094 for (int column
= start_column
; column
<= finish_column
; column
++)
1096 m_colorizer
.set_fixit_hint ();
1097 pp_character (m_pp
, '-');
1098 m_colorizer
.set_normal_text ();
1103 case fixit_hint::REPLACE
:
1105 fixit_replace
*replace
= static_cast <fixit_replace
*> (hint
);
1107 = LOCATION_COLUMN (replace
->get_range ().m_start
);
1108 move_to_column (&column
, start_column
);
1109 m_colorizer
.set_fixit_hint ();
1110 pp_string (m_pp
, replace
->get_string ());
1111 m_colorizer
.set_normal_text ();
1112 column
+= replace
->get_length ();
1122 /* Add a trailing newline, if necessary. */
1123 move_to_column (&column
, 0);
1126 /* Disable any colorization and emit a newline. */
1129 layout::print_newline ()
1131 m_colorizer
.set_normal_text ();
1135 /* Return true if (ROW/COLUMN) is within a range of the layout.
1136 If it returns true, OUT_STATE is written to, with the
1137 range index, and whether we should draw the caret at
1138 (ROW/COLUMN) (as opposed to an underline). */
1141 layout::get_state_at_point (/* Inputs. */
1142 int row
, int column
,
1143 int first_non_ws
, int last_non_ws
,
1145 point_state
*out_state
)
1147 layout_range
*range
;
1149 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1151 if (range
->contains_point (row
, column
))
1153 out_state
->range_idx
= i
;
1155 /* Are we at the range's caret? is it visible? */
1156 out_state
->draw_caret_p
= false;
1157 if (range
->m_show_caret_p
1158 && row
== range
->m_caret
.m_line
1159 && column
== range
->m_caret
.m_column
)
1160 out_state
->draw_caret_p
= true;
1162 /* Within a multiline range, don't display any underline
1163 in any leading or trailing whitespace on a line.
1164 We do display carets, however. */
1165 if (!out_state
->draw_caret_p
)
1166 if (column
< first_non_ws
|| column
> last_non_ws
)
1169 /* We are within a range. */
1177 /* Helper function for use by layout::print_line when printing the
1178 annotation line under the source line.
1179 Get the column beyond the rightmost one that could contain a caret or
1180 range marker, given that we stop rendering at trailing whitespace.
1181 ROW is the source line within the given file.
1182 CARET_COLUMN is the column of range 0's caret.
1183 LAST_NON_WS_COLUMN is the last column containing a non-whitespace
1184 character of source (as determined when printing the source line). */
1187 layout::get_x_bound_for_row (int row
, int caret_column
,
1188 int last_non_ws_column
)
1190 int result
= caret_column
+ 1;
1192 layout_range
*range
;
1194 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1196 if (row
>= range
->m_start
.m_line
)
1198 if (range
->m_finish
.m_line
== row
)
1200 /* On the final line within a range; ensure that
1201 we render up to the end of the range. */
1202 if (result
<= range
->m_finish
.m_column
)
1203 result
= range
->m_finish
.m_column
+ 1;
1205 else if (row
< range
->m_finish
.m_line
)
1207 /* Within a multiline range; ensure that we render up to the
1208 last non-whitespace column. */
1209 if (result
<= last_non_ws_column
)
1210 result
= last_non_ws_column
+ 1;
1218 /* Given *COLUMN as an x-coordinate, print spaces to position
1219 successive output at DEST_COLUMN, printing a newline if necessary,
1220 and updating *COLUMN. */
1223 layout::move_to_column (int *column
, int dest_column
)
1225 /* Start a new line if we need to. */
1226 if (*column
> dest_column
)
1232 while (*column
< dest_column
)
1239 /* For debugging layout issues, render a ruler giving column numbers
1240 (after the 1-column indent). */
1243 layout::show_ruler (int max_column
) const
1246 if (max_column
> 99)
1249 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
1250 if (0 == column
% 10)
1251 pp_character (m_pp
, '0' + (column
/ 100) % 10);
1259 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
1260 if (0 == column
% 10)
1261 pp_character (m_pp
, '0' + (column
/ 10) % 10);
1268 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
1269 pp_character (m_pp
, '0' + (column
% 10));
1273 } /* End of anonymous namespace. */
1275 /* Print the physical source code corresponding to the location of
1276 this diagnostic, with additional annotations. */
1279 diagnostic_show_locus (diagnostic_context
* context
,
1280 rich_location
*richloc
,
1281 diagnostic_t diagnostic_kind
)
1283 pp_newline (context
->printer
);
1285 location_t loc
= richloc
->get_loc ();
1286 /* Do nothing if source-printing has been disabled. */
1287 if (!context
->show_caret
)
1290 /* Don't attempt to print source for UNKNOWN_LOCATION and for builtins. */
1291 if (loc
<= BUILTINS_LOCATION
)
1294 /* Don't print the same source location twice in a row, unless we have
1296 if (loc
== context
->last_location
1297 && richloc
->get_num_fixit_hints () == 0)
1300 context
->last_location
= loc
;
1302 const char *saved_prefix
= pp_get_prefix (context
->printer
);
1303 pp_set_prefix (context
->printer
, NULL
);
1305 layout
layout (context
, richloc
, diagnostic_kind
);
1306 for (int line_span_idx
= 0; line_span_idx
< layout
.get_num_line_spans ();
1309 const line_span
*line_span
= layout
.get_line_span (line_span_idx
);
1310 if (layout
.print_heading_for_line_span_index_p (line_span_idx
))
1312 expanded_location exploc
= layout
.get_expanded_location (line_span
);
1313 context
->start_span (context
, exploc
);
1315 int last_line
= line_span
->get_last_line ();
1316 for (int row
= line_span
->get_first_line (); row
<= last_line
; row
++)
1318 /* Print the source line, followed by an annotation line
1319 consisting of any caret/underlines, then any fixits.
1320 If the source line can't be read, print nothing. */
1321 line_bounds lbounds
;
1322 if (layout
.print_source_line (row
, &lbounds
))
1324 layout
.print_annotation_line (row
, lbounds
);
1325 layout
.print_any_fixits (row
, richloc
);
1330 pp_set_prefix (context
->printer
, saved_prefix
);
1335 namespace selftest
{
1337 /* Selftests for diagnostic_show_locus. */
1339 /* Convenience subclass of diagnostic_context for testing
1340 diagnostic_show_locus. */
1342 class test_diagnostic_context
: public diagnostic_context
1345 test_diagnostic_context ()
1347 diagnostic_initialize (this, 0);
1350 ~test_diagnostic_context ()
1352 diagnostic_finish (this);
1356 /* Verify that diagnostic_show_locus works sanely on UNKNOWN_LOCATION. */
1359 test_diagnostic_show_locus_unknown_location ()
1361 test_diagnostic_context dc
;
1362 rich_location
richloc (line_table
, UNKNOWN_LOCATION
);
1363 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1364 ASSERT_STREQ ("\n", pp_formatted_text (dc
.printer
));
1367 /* Verify that diagnostic_show_locus works sanely for various
1370 All of these work on the following 1-line source file:
1373 "foo = bar.field;\n"
1374 which is set up by test_diagnostic_show_locus_one_liner and calls
1380 test_one_liner_simple_caret ()
1382 test_diagnostic_context dc
;
1383 location_t caret
= linemap_position_for_column (line_table
, 10);
1384 rich_location
richloc (line_table
, caret
);
1385 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1387 " foo = bar.field;\n"
1389 pp_formatted_text (dc
.printer
));
1392 /* Caret and range. */
1395 test_one_liner_caret_and_range ()
1397 test_diagnostic_context dc
;
1398 location_t caret
= linemap_position_for_column (line_table
, 10);
1399 location_t start
= linemap_position_for_column (line_table
, 7);
1400 location_t finish
= linemap_position_for_column (line_table
, 15);
1401 location_t loc
= make_location (caret
, start
, finish
);
1402 rich_location
richloc (line_table
, loc
);
1403 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1405 " foo = bar.field;\n"
1407 pp_formatted_text (dc
.printer
));
1410 /* Multiple ranges and carets. */
1413 test_one_liner_multiple_carets_and_ranges ()
1415 test_diagnostic_context dc
;
1417 = make_location (linemap_position_for_column (line_table
, 2),
1418 linemap_position_for_column (line_table
, 1),
1419 linemap_position_for_column (line_table
, 3));
1420 dc
.caret_chars
[0] = 'A';
1423 = make_location (linemap_position_for_column (line_table
, 8),
1424 linemap_position_for_column (line_table
, 7),
1425 linemap_position_for_column (line_table
, 9));
1426 dc
.caret_chars
[1] = 'B';
1429 = make_location (linemap_position_for_column (line_table
, 13),
1430 linemap_position_for_column (line_table
, 11),
1431 linemap_position_for_column (line_table
, 15));
1432 dc
.caret_chars
[2] = 'C';
1434 rich_location
richloc (line_table
, foo
);
1435 richloc
.add_range (bar
, true);
1436 richloc
.add_range (field
, true);
1437 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1439 " foo = bar.field;\n"
1441 pp_formatted_text (dc
.printer
));
1444 /* Insertion fix-it hint: adding an "&" to the front of "bar.field". */
1447 test_one_liner_fixit_insert ()
1449 test_diagnostic_context dc
;
1450 location_t caret
= linemap_position_for_column (line_table
, 7);
1451 rich_location
richloc (line_table
, caret
);
1452 richloc
.add_fixit_insert (caret
, "&");
1453 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1455 " foo = bar.field;\n"
1458 pp_formatted_text (dc
.printer
));
1461 /* Removal fix-it hint: removal of the ".field". */
1464 test_one_liner_fixit_remove ()
1466 test_diagnostic_context dc
;
1467 location_t start
= linemap_position_for_column (line_table
, 10);
1468 location_t finish
= linemap_position_for_column (line_table
, 15);
1469 location_t dot
= make_location (start
, start
, finish
);
1470 rich_location
richloc (line_table
, dot
);
1472 range
.m_start
= start
;
1473 range
.m_finish
= finish
;
1474 richloc
.add_fixit_remove (range
);
1475 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1477 " foo = bar.field;\n"
1480 pp_formatted_text (dc
.printer
));
1483 /* Replace fix-it hint: replacing "field" with "m_field". */
1486 test_one_liner_fixit_replace ()
1488 test_diagnostic_context dc
;
1489 location_t start
= linemap_position_for_column (line_table
, 11);
1490 location_t finish
= linemap_position_for_column (line_table
, 15);
1491 location_t field
= make_location (start
, start
, finish
);
1492 rich_location
richloc (line_table
, field
);
1494 range
.m_start
= start
;
1495 range
.m_finish
= finish
;
1496 richloc
.add_fixit_replace (range
, "m_field");
1497 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1499 " foo = bar.field;\n"
1502 pp_formatted_text (dc
.printer
));
1505 /* Run the various one-liner tests. */
1508 test_diagnostic_show_locus_one_liner (const line_table_case
&case_
)
1510 /* Create a tempfile and write some text to it.
1511 ....................0000000001111111.
1512 ....................1234567890123456. */
1513 const char *content
= "foo = bar.field;\n";
1514 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
1515 line_table_test
ltt (case_
);
1517 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 1);
1519 location_t line_end
= linemap_position_for_column (line_table
, 16);
1521 /* Don't attempt to run the tests if column data might be unavailable. */
1522 if (line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
1525 ASSERT_STREQ (tmp
.get_filename (), LOCATION_FILE (line_end
));
1526 ASSERT_EQ (1, LOCATION_LINE (line_end
));
1527 ASSERT_EQ (16, LOCATION_COLUMN (line_end
));
1529 test_one_liner_simple_caret ();
1530 test_one_liner_caret_and_range ();
1531 test_one_liner_multiple_carets_and_ranges ();
1532 test_one_liner_fixit_insert ();
1533 test_one_liner_fixit_remove ();
1534 test_one_liner_fixit_replace ();
1537 /* Run all of the selftests within this file. */
1540 diagnostic_show_locus_c_tests ()
1542 test_range_contains_point_for_single_point ();
1543 test_range_contains_point_for_single_line ();
1544 test_range_contains_point_for_multiple_lines ();
1546 test_get_line_width_without_trailing_whitespace ();
1548 test_diagnostic_show_locus_unknown_location ();
1550 for_each_line_table_case (test_diagnostic_show_locus_one_liner
);
1553 } // namespace selftest
1555 #endif /* #if CHECKING_P */