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 bool annotation_line_showed_range_p (int line
, int start_column
,
203 int finish_column
) const;
204 void print_any_fixits (int row
, const rich_location
*richloc
);
206 void show_ruler (int max_column
) const;
209 void calculate_line_spans ();
211 void print_newline ();
214 get_state_at_point (/* Inputs. */
216 int first_non_ws
, int last_non_ws
,
218 point_state
*out_state
);
221 get_x_bound_for_row (int row
, int caret_column
,
225 move_to_column (int *column
, int dest_column
);
228 diagnostic_context
*m_context
;
229 pretty_printer
*m_pp
;
230 diagnostic_t m_diagnostic_kind
;
231 expanded_location m_exploc
;
232 colorizer m_colorizer
;
233 bool m_colorize_source_p
;
234 auto_vec
<layout_range
> m_layout_ranges
;
235 auto_vec
<line_span
> m_line_spans
;
239 /* Implementation of "class colorizer". */
241 /* The constructor for "colorizer". Lookup and store color codes for the
242 different kinds of things we might need to print. */
244 colorizer::colorizer (diagnostic_context
*context
,
245 diagnostic_t diagnostic_kind
) :
247 m_diagnostic_kind (diagnostic_kind
),
248 m_current_state (STATE_NORMAL_TEXT
)
250 m_caret_ce
= colorize_stop (pp_show_color (context
->printer
));
251 m_range1_cs
= colorize_start (pp_show_color (context
->printer
), "range1");
252 m_range2_cs
= colorize_start (pp_show_color (context
->printer
), "range2");
253 m_range_ce
= colorize_stop (pp_show_color (context
->printer
));
256 /* The destructor for "colorize". If colorization is on, print a code to
259 colorizer::~colorizer ()
261 finish_state (m_current_state
);
264 /* Update state, printing color codes if necessary if there's a state
268 colorizer::set_state (int new_state
)
270 if (m_current_state
!= new_state
)
272 finish_state (m_current_state
);
273 m_current_state
= new_state
;
274 begin_state (new_state
);
278 /* Turn on any colorization for STATE. */
281 colorizer::begin_state (int state
)
285 case STATE_NORMAL_TEXT
:
289 /* Make range 0 be the same color as the "kind" text
290 (error vs warning vs note). */
293 colorize_start (pp_show_color (m_context
->printer
),
294 diagnostic_get_color_for_kind (m_diagnostic_kind
)));
298 pp_string (m_context
->printer
, m_range1_cs
);
302 pp_string (m_context
->printer
, m_range2_cs
);
306 /* We don't expect more than 3 ranges per diagnostic. */
312 /* Turn off any colorization for STATE. */
315 colorizer::finish_state (int state
)
319 case STATE_NORMAL_TEXT
:
323 pp_string (m_context
->printer
, m_caret_ce
);
327 /* Within a range. */
328 gcc_assert (state
> 0);
329 pp_string (m_context
->printer
, m_range_ce
);
334 /* Implementation of class layout_range. */
336 /* The constructor for class layout_range.
337 Initialize various layout_point fields from expanded_location
338 equivalents; we've already filtered on file. */
340 layout_range::layout_range (const expanded_location
*start_exploc
,
341 const expanded_location
*finish_exploc
,
343 const expanded_location
*caret_exploc
)
344 : m_start (*start_exploc
),
345 m_finish (*finish_exploc
),
346 m_show_caret_p (show_caret_p
),
347 m_caret (*caret_exploc
)
351 /* Is (column, row) within the given range?
352 We've already filtered on the file.
354 Ranges are closed (both limits are within the range).
356 Example A: a single-line range:
357 start: (col=22, line=2)
358 finish: (col=38, line=2)
360 |00000011111111112222222222333333333344444444444
361 |34567890123456789012345678901234567890123456789
362 --+-----------------------------------------------
363 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
364 02|bbbbbbbbbbbbbbbbbbbSwwwwwwwwwwwwwwwFaaaaaaaaaaa
365 03|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
367 Example B: a multiline range with
368 start: (col=14, line=3)
369 finish: (col=08, line=5)
371 |00000011111111112222222222333333333344444444444
372 |34567890123456789012345678901234567890123456789
373 --+-----------------------------------------------
374 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
375 02|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
376 03|bbbbbbbbbbbSwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
377 04|wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
378 05|wwwwwFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
379 06|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
380 --+-----------------------------------------------
383 - 'b' indicates a point *before* the range
384 - 'S' indicates the start of the range
385 - 'w' indicates a point within the range
386 - 'F' indicates the finish of the range (which is
388 - 'a' indicates a subsequent point *after* the range. */
391 layout_range::contains_point (int row
, int column
) const
393 gcc_assert (m_start
.m_line
<= m_finish
.m_line
);
394 /* ...but the equivalent isn't true for the columns;
395 consider example B in the comment above. */
397 if (row
< m_start
.m_line
)
398 /* Points before the first line of the range are
399 outside it (corresponding to line 01 in example A
400 and lines 01 and 02 in example B above). */
403 if (row
== m_start
.m_line
)
404 /* On same line as start of range (corresponding
405 to line 02 in example A and line 03 in example B). */
407 if (column
< m_start
.m_column
)
408 /* Points on the starting line of the range, but
409 before the column in which it begins. */
412 if (row
< m_finish
.m_line
)
413 /* This is a multiline range; the point
414 is within it (corresponds to line 03 in example B
415 from column 14 onwards) */
419 /* This is a single-line range. */
420 gcc_assert (row
== m_finish
.m_line
);
421 return column
<= m_finish
.m_column
;
425 /* The point is in a line beyond that containing the
426 start of the range: lines 03 onwards in example A,
427 and lines 04 onwards in example B. */
428 gcc_assert (row
> m_start
.m_line
);
430 if (row
> m_finish
.m_line
)
431 /* The point is beyond the final line of the range
432 (lines 03 onwards in example A, and lines 06 onwards
436 if (row
< m_finish
.m_line
)
438 /* The point is in a line that's fully within a multiline
439 range (e.g. line 04 in example B). */
440 gcc_assert (m_start
.m_line
< m_finish
.m_line
);
444 gcc_assert (row
== m_finish
.m_line
);
446 return column
<= m_finish
.m_column
;
451 /* A helper function for testing layout_range::contains_point. */
454 make_range (int start_line
, int start_col
, int end_line
, int end_col
)
456 const expanded_location start_exploc
457 = {"test.c", start_line
, start_col
, NULL
, false};
458 const expanded_location finish_exploc
459 = {"test.c", end_line
, end_col
, NULL
, false};
460 return layout_range (&start_exploc
, &finish_exploc
, false,
464 /* Selftests for layout_range::contains_point. */
466 /* Selftest for layout_range::contains_point where the layout_range
467 is a range with start==end i.e. a single point. */
470 test_range_contains_point_for_single_point ()
472 layout_range point
= make_range (7, 10, 7, 10);
474 /* Before the line. */
475 ASSERT_FALSE (point
.contains_point (6, 1));
477 /* On the line, but before start. */
478 ASSERT_FALSE (point
.contains_point (7, 9));
481 ASSERT_TRUE (point
.contains_point (7, 10));
483 /* On the line, after the point. */
484 ASSERT_FALSE (point
.contains_point (7, 11));
486 /* After the line. */
487 ASSERT_FALSE (point
.contains_point (8, 1));
490 /* Selftest for layout_range::contains_point where the layout_range
491 is the single-line range shown as "Example A" above. */
494 test_range_contains_point_for_single_line ()
496 layout_range example_a
= make_range (2, 22, 2, 38);
498 /* Before the line. */
499 ASSERT_FALSE (example_a
.contains_point (1, 1));
501 /* On the line, but before start. */
502 ASSERT_FALSE (example_a
.contains_point (2, 21));
504 /* On the line, at the start. */
505 ASSERT_TRUE (example_a
.contains_point (2, 22));
507 /* On the line, within the range. */
508 ASSERT_TRUE (example_a
.contains_point (2, 23));
510 /* On the line, at the end. */
511 ASSERT_TRUE (example_a
.contains_point (2, 38));
513 /* On the line, after the end. */
514 ASSERT_FALSE (example_a
.contains_point (2, 39));
516 /* After the line. */
517 ASSERT_FALSE (example_a
.contains_point (2, 39));
520 /* Selftest for layout_range::contains_point where the layout_range
521 is the multi-line range shown as "Example B" above. */
524 test_range_contains_point_for_multiple_lines ()
526 layout_range example_b
= make_range (3, 14, 5, 8);
528 /* Before first line. */
529 ASSERT_FALSE (example_b
.contains_point (1, 1));
531 /* On the first line, but before start. */
532 ASSERT_FALSE (example_b
.contains_point (3, 13));
535 ASSERT_TRUE (example_b
.contains_point (3, 14));
537 /* On the first line, within the range. */
538 ASSERT_TRUE (example_b
.contains_point (3, 15));
540 /* On an interior line.
541 The column number should not matter; try various boundary
543 ASSERT_TRUE (example_b
.contains_point (4, 1));
544 ASSERT_TRUE (example_b
.contains_point (4, 7));
545 ASSERT_TRUE (example_b
.contains_point (4, 8));
546 ASSERT_TRUE (example_b
.contains_point (4, 9));
547 ASSERT_TRUE (example_b
.contains_point (4, 13));
548 ASSERT_TRUE (example_b
.contains_point (4, 14));
549 ASSERT_TRUE (example_b
.contains_point (4, 15));
551 /* On the final line, before the end. */
552 ASSERT_TRUE (example_b
.contains_point (5, 7));
554 /* On the final line, at the end. */
555 ASSERT_TRUE (example_b
.contains_point (5, 8));
557 /* On the final line, after the end. */
558 ASSERT_FALSE (example_b
.contains_point (5, 9));
560 /* After the line. */
561 ASSERT_FALSE (example_b
.contains_point (6, 1));
564 #endif /* #if CHECKING_P */
566 /* Given a source line LINE of length LINE_WIDTH, determine the width
567 without any trailing whitespace. */
570 get_line_width_without_trailing_whitespace (const char *line
, int line_width
)
572 int result
= line_width
;
575 char ch
= line
[result
- 1];
576 if (ch
== ' ' || ch
== '\t')
581 gcc_assert (result
>= 0);
582 gcc_assert (result
<= line_width
);
583 gcc_assert (result
== 0 ||
584 (line
[result
- 1] != ' '
585 && line
[result
-1] != '\t'));
591 /* A helper function for testing get_line_width_without_trailing_whitespace. */
594 assert_eq (const char *line
, int expected_width
)
597 = get_line_width_without_trailing_whitespace (line
, strlen (line
));
598 ASSERT_EQ (actual_value
, expected_width
);
601 /* Verify that get_line_width_without_trailing_whitespace is sane for
602 various inputs. It is not required to handle newlines. */
605 test_get_line_width_without_trailing_whitespace ()
610 assert_eq ("hello world", 11);
611 assert_eq ("hello world ", 11);
612 assert_eq ("hello world \t\t ", 11);
615 #endif /* #if CHECKING_P */
617 /* Helper function for layout's ctor, for sanitizing locations relative
618 to the primary location within a diagnostic.
620 Compare LOC_A and LOC_B to see if it makes sense to print underlines
621 connecting their expanded locations. Doing so is only guaranteed to
622 make sense if the locations share the same macro expansion "history"
623 i.e. they can be traced through the same macro expansions, eventually
624 reaching an ordinary map.
626 This may be too strong a condition, but it effectively sanitizes
627 PR c++/70105, which has an example of printing an expression where the
628 final location of the expression is in a different macro, which
629 erroneously was leading to hundreds of lines of irrelevant source
633 compatible_locations_p (location_t loc_a
, location_t loc_b
)
635 if (IS_ADHOC_LOC (loc_a
))
636 loc_a
= get_location_from_adhoc_loc (line_table
, loc_a
);
637 if (IS_ADHOC_LOC (loc_b
))
638 loc_b
= get_location_from_adhoc_loc (line_table
, loc_b
);
640 /* If either location is one of the special locations outside of a
641 linemap, they are only compatible if they are equal. */
642 if (loc_a
< RESERVED_LOCATION_COUNT
643 || loc_b
< RESERVED_LOCATION_COUNT
)
644 return loc_a
== loc_b
;
646 const line_map
*map_a
= linemap_lookup (line_table
, loc_a
);
647 linemap_assert (map_a
);
649 const line_map
*map_b
= linemap_lookup (line_table
, loc_b
);
650 linemap_assert (map_b
);
652 /* Are they within the same map? */
655 /* Are both within the same macro expansion? */
656 if (linemap_macro_expansion_map_p (map_a
))
658 /* Expand each location towards the spelling location, and
660 const line_map_macro
*macro_map
= linemap_check_macro (map_a
);
661 source_location loc_a_toward_spelling
662 = linemap_macro_map_loc_unwind_toward_spelling (line_table
,
665 source_location loc_b_toward_spelling
666 = linemap_macro_map_loc_unwind_toward_spelling (line_table
,
669 return compatible_locations_p (loc_a_toward_spelling
,
670 loc_b_toward_spelling
);
673 /* Otherwise they are within the same ordinary map. */
678 /* Within different maps. */
680 /* If either is within a macro expansion, they are incompatible. */
681 if (linemap_macro_expansion_map_p (map_a
)
682 || linemap_macro_expansion_map_p (map_b
))
685 /* Within two different ordinary maps; they are compatible iff they
686 are in the same file. */
687 const line_map_ordinary
*ord_map_a
= linemap_check_ordinary (map_a
);
688 const line_map_ordinary
*ord_map_b
= linemap_check_ordinary (map_b
);
689 return ord_map_a
->to_file
== ord_map_b
->to_file
;
693 /* Implementation of class layout. */
695 /* Constructor for class layout.
697 Filter the ranges from the rich_location to those that we can
698 sanely print, populating m_layout_ranges.
699 Determine the range of lines that we will print, splitting them
700 up into an ordered list of disjoint spans of contiguous line numbers.
701 Determine m_x_offset, to ensure that the primary caret
702 will fit within the max_width provided by the diagnostic_context. */
704 layout::layout (diagnostic_context
* context
,
705 rich_location
*richloc
,
706 diagnostic_t diagnostic_kind
)
707 : m_context (context
),
708 m_pp (context
->printer
),
709 m_diagnostic_kind (diagnostic_kind
),
710 m_exploc (richloc
->get_expanded_location (0)),
711 m_colorizer (context
, diagnostic_kind
),
712 m_colorize_source_p (context
->colorize_source_p
),
713 m_layout_ranges (rich_location::MAX_RANGES
),
714 m_line_spans (1 + rich_location::MAX_RANGES
),
717 source_location primary_loc
= richloc
->get_range (0)->m_loc
;
719 for (unsigned int idx
= 0; idx
< richloc
->get_num_locations (); idx
++)
721 /* This diagnostic printer can only cope with "sufficiently sane" ranges.
722 Ignore any ranges that are awkward to handle. */
723 const location_range
*loc_range
= richloc
->get_range (idx
);
725 /* Split the "range" into caret and range information. */
726 source_range src_range
= get_range_from_loc (line_table
, loc_range
->m_loc
);
728 /* Expand the various locations. */
729 expanded_location start
730 = linemap_client_expand_location_to_spelling_point (src_range
.m_start
);
731 expanded_location finish
732 = linemap_client_expand_location_to_spelling_point (src_range
.m_finish
);
733 expanded_location caret
734 = linemap_client_expand_location_to_spelling_point (loc_range
->m_loc
);
736 /* If any part of the range isn't in the same file as the primary
737 location of this diagnostic, ignore the range. */
738 if (start
.file
!= m_exploc
.file
)
740 if (finish
.file
!= m_exploc
.file
)
742 if (loc_range
->m_show_caret_p
)
743 if (caret
.file
!= m_exploc
.file
)
746 /* Sanitize the caret location for non-primary ranges. */
747 if (m_layout_ranges
.length () > 0)
748 if (loc_range
->m_show_caret_p
)
749 if (!compatible_locations_p (loc_range
->m_loc
, primary_loc
))
750 /* Discard any non-primary ranges that can't be printed
751 sanely relative to the primary location. */
754 /* Everything is now known to be in the correct source file,
755 but it may require further sanitization. */
756 layout_range
ri (&start
, &finish
, loc_range
->m_show_caret_p
, &caret
);
758 /* If we have a range that finishes before it starts (perhaps
759 from something built via macro expansion), printing the
760 range is likely to be nonsensical. Also, attempting to do so
761 breaks assumptions within the printing code (PR c/68473).
762 Similarly, don't attempt to print ranges if one or both ends
763 of the range aren't sane to print relative to the
764 primary location (PR c++/70105). */
765 if (start
.line
> finish
.line
766 || !compatible_locations_p (src_range
.m_start
, primary_loc
)
767 || !compatible_locations_p (src_range
.m_finish
, primary_loc
))
769 /* Is this the primary location? */
770 if (m_layout_ranges
.length () == 0)
772 /* We want to print the caret for the primary location, but
773 we must sanitize away m_start and m_finish. */
774 ri
.m_start
= ri
.m_caret
;
775 ri
.m_finish
= ri
.m_caret
;
778 /* This is a non-primary range; ignore it. */
782 /* Passed all the tests; add the range to m_layout_ranges so that
783 it will be printed. */
784 m_layout_ranges
.safe_push (ri
);
787 /* Populate m_line_spans. */
788 calculate_line_spans ();
790 /* Adjust m_x_offset.
791 Center the primary caret to fit in max_width; all columns
792 will be adjusted accordingly. */
793 int max_width
= m_context
->caret_max_width
;
795 const char *line
= location_get_source_line (m_exploc
.file
, m_exploc
.line
,
797 if (line
&& m_exploc
.column
<= line_width
)
799 int right_margin
= CARET_LINE_MARGIN
;
800 int column
= m_exploc
.column
;
801 right_margin
= MIN (line_width
- column
, right_margin
);
802 right_margin
= max_width
- right_margin
;
803 if (line_width
>= max_width
&& column
> right_margin
)
804 m_x_offset
= column
- right_margin
;
805 gcc_assert (m_x_offset
>= 0);
808 if (context
->show_ruler_p
)
809 show_ruler (m_x_offset
+ max_width
);
812 /* Return true iff we should print a heading when starting the
813 line span with the given index. */
816 layout::print_heading_for_line_span_index_p (int line_span_idx
) const
818 /* We print a heading for every change of line span, hence for every
819 line span after the initial one. */
820 if (line_span_idx
> 0)
823 /* We also do it for the initial span if the primary location of the
824 diagnostic is in a different span. */
825 if (m_exploc
.line
> (int)get_line_span (0)->m_last_line
)
831 /* Get an expanded_location for the first location of interest within
833 Used when printing a heading to indicate a new line span. */
836 layout::get_expanded_location (const line_span
*line_span
) const
838 /* Whenever possible, use the caret location. */
839 if (line_span
->contains_line_p (m_exploc
.line
))
842 /* Otherwise, use the start of the first range that's present
843 within the line_span. */
844 for (unsigned int i
= 0; i
< m_layout_ranges
.length (); i
++)
846 const layout_range
*lr
= &m_layout_ranges
[i
];
847 if (line_span
->contains_line_p (lr
->m_start
.m_line
))
849 expanded_location exploc
= m_exploc
;
850 exploc
.line
= lr
->m_start
.m_line
;
851 exploc
.column
= lr
->m_start
.m_column
;
856 /* It should not be possible to have a line span that didn't
857 contain any of the layout_range instances. */
862 /* We want to print the pertinent source code at a diagnostic. The
863 rich_location can contain multiple locations. This will have been
864 filtered into m_exploc (the caret for the primary location) and
865 m_layout_ranges, for those ranges within the same source file.
867 We will print a subset of the lines within the source file in question,
868 as a collection of "spans" of lines.
870 This function populates m_line_spans with an ordered, disjoint list of
871 the line spans of interest.
873 For example, if the primary caret location is on line 7, with ranges
874 covering lines 5-6 and lines 9-12:
887 then we want two spans: lines 5-7 and lines 9-12. */
890 layout::calculate_line_spans ()
892 /* This should only be called once, by the ctor. */
893 gcc_assert (m_line_spans
.length () == 0);
895 /* Populate tmp_spans with individual spans, for each of
896 m_exploc, and for m_layout_ranges. */
897 auto_vec
<line_span
> tmp_spans (1 + rich_location::MAX_RANGES
);
898 tmp_spans
.safe_push (line_span (m_exploc
.line
, m_exploc
.line
));
899 for (unsigned int i
= 0; i
< m_layout_ranges
.length (); i
++)
901 const layout_range
*lr
= &m_layout_ranges
[i
];
902 gcc_assert (lr
->m_start
.m_line
<= lr
->m_finish
.m_line
);
903 tmp_spans
.safe_push (line_span (lr
->m_start
.m_line
,
904 lr
->m_finish
.m_line
));
908 tmp_spans
.qsort(line_span::comparator
);
910 /* Now iterate through tmp_spans, copying into m_line_spans, and
911 combining where possible. */
912 gcc_assert (tmp_spans
.length () > 0);
913 m_line_spans
.safe_push (tmp_spans
[0]);
914 for (unsigned int i
= 1; i
< tmp_spans
.length (); i
++)
916 line_span
*current
= &m_line_spans
[m_line_spans
.length () - 1];
917 const line_span
*next
= &tmp_spans
[i
];
918 gcc_assert (next
->m_first_line
>= current
->m_first_line
);
919 if (next
->m_first_line
<= current
->m_last_line
+ 1)
921 /* We can merge them. */
922 if (next
->m_last_line
> current
->m_last_line
)
923 current
->m_last_line
= next
->m_last_line
;
927 /* No merger possible. */
928 m_line_spans
.safe_push (*next
);
932 /* Verify the result, in m_line_spans. */
933 gcc_assert (m_line_spans
.length () > 0);
934 for (unsigned int i
= 1; i
< m_line_spans
.length (); i
++)
936 const line_span
*prev
= &m_line_spans
[i
- 1];
937 const line_span
*next
= &m_line_spans
[i
];
938 /* The individual spans must be sane. */
939 gcc_assert (prev
->m_first_line
<= prev
->m_last_line
);
940 gcc_assert (next
->m_first_line
<= next
->m_last_line
);
941 /* The spans must be ordered. */
942 gcc_assert (prev
->m_first_line
< next
->m_first_line
);
943 /* There must be a gap of at least one line between separate spans. */
944 gcc_assert ((prev
->m_last_line
+ 1) < next
->m_first_line
);
948 /* Attempt to print line ROW of source code, potentially colorized at any
950 Return true if the line was printed, populating *LBOUNDS_OUT.
951 Return false if the source line could not be read, leaving *LBOUNDS_OUT
955 layout::print_source_line (int row
, line_bounds
*lbounds_out
)
958 const char *line
= location_get_source_line (m_exploc
.file
, row
,
963 m_colorizer
.set_normal_text ();
965 /* We will stop printing the source line at any trailing
967 line_width
= get_line_width_without_trailing_whitespace (line
,
972 int first_non_ws
= INT_MAX
;
975 for (column
= 1 + m_x_offset
; column
<= line_width
; column
++)
977 /* Assuming colorization is enabled for the caret and underline
978 characters, we may also colorize the associated characters
979 within the source line.
981 For frontends that generate range information, we color the
982 associated characters in the source line the same as the
983 carets and underlines in the annotation line, to make it easier
984 for the reader to see the pertinent code.
986 For frontends that only generate carets, we don't colorize the
987 characters above them, since this would look strange (e.g.
988 colorizing just the first character in a token). */
989 if (m_colorize_source_p
)
993 in_range_p
= get_state_at_point (row
, column
,
997 m_colorizer
.set_range (state
.range_idx
);
999 m_colorizer
.set_normal_text ();
1001 char c
= *line
== '\t' ? ' ' : *line
;
1006 last_non_ws
= column
;
1007 if (first_non_ws
== INT_MAX
)
1008 first_non_ws
= column
;
1010 pp_character (m_pp
, c
);
1015 lbounds_out
->m_first_non_ws
= first_non_ws
;
1016 lbounds_out
->m_last_non_ws
= last_non_ws
;
1020 /* Print a line consisting of the caret/underlines for the given
1024 layout::print_annotation_line (int row
, const line_bounds lbounds
)
1026 int x_bound
= get_x_bound_for_row (row
, m_exploc
.column
,
1027 lbounds
.m_last_non_ws
);
1030 for (int column
= 1 + m_x_offset
; column
< x_bound
; column
++)
1034 in_range_p
= get_state_at_point (row
, column
,
1035 lbounds
.m_first_non_ws
,
1036 lbounds
.m_last_non_ws
,
1040 /* Within a range. Draw either the caret or an underline. */
1041 m_colorizer
.set_range (state
.range_idx
);
1042 if (state
.draw_caret_p
)
1043 /* Draw the caret. */
1044 pp_character (m_pp
, m_context
->caret_chars
[state
.range_idx
]);
1046 pp_character (m_pp
, '~');
1050 /* Not in a range. */
1051 m_colorizer
.set_normal_text ();
1052 pp_character (m_pp
, ' ');
1058 /* Subroutine of layout::print_any_fixits.
1060 Determine if the annotation line printed for LINE contained
1061 the exact range from START_COLUMN to FINISH_COLUMN. */
1064 layout::annotation_line_showed_range_p (int line
, int start_column
,
1065 int finish_column
) const
1067 layout_range
*range
;
1069 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1070 if (range
->m_start
.m_line
== line
1071 && range
->m_start
.m_column
== start_column
1072 && range
->m_finish
.m_line
== line
1073 && range
->m_finish
.m_column
== finish_column
)
1078 /* If there are any fixit hints on source line ROW within RICHLOC, print them.
1079 They are printed in order, attempting to combine them onto lines, but
1080 starting new lines if necessary. */
1083 layout::print_any_fixits (int row
, const rich_location
*richloc
)
1086 for (unsigned int i
= 0; i
< richloc
->get_num_fixit_hints (); i
++)
1088 fixit_hint
*hint
= richloc
->get_fixit_hint (i
);
1089 if (hint
->affects_line_p (m_exploc
.file
, row
))
1091 /* For now we assume each fixit hint can only touch one line. */
1092 switch (hint
->get_kind ())
1094 case fixit_hint::INSERT
:
1096 fixit_insert
*insert
= static_cast <fixit_insert
*> (hint
);
1097 /* This assumes the insertion just affects one line. */
1099 = LOCATION_COLUMN (insert
->get_location ());
1100 move_to_column (&column
, start_column
);
1101 m_colorizer
.set_fixit_hint ();
1102 pp_string (m_pp
, insert
->get_string ());
1103 m_colorizer
.set_normal_text ();
1104 column
+= insert
->get_length ();
1108 case fixit_hint::REPLACE
:
1110 fixit_replace
*replace
= static_cast <fixit_replace
*> (hint
);
1111 source_range src_range
= replace
->get_range ();
1112 int line
= LOCATION_LINE (src_range
.m_start
);
1113 int start_column
= LOCATION_COLUMN (src_range
.m_start
);
1114 int finish_column
= LOCATION_COLUMN (src_range
.m_finish
);
1116 /* If the range of the replacement wasn't printed in the
1117 annotation line, then print an extra underline to
1118 indicate exactly what is being replaced.
1119 Always show it for removals. */
1120 if (!annotation_line_showed_range_p (line
, start_column
,
1122 || replace
->get_length () == 0)
1124 move_to_column (&column
, start_column
);
1125 m_colorizer
.set_fixit_hint ();
1126 for (; column
<= finish_column
; column
++)
1127 pp_character (m_pp
, '-');
1128 m_colorizer
.set_normal_text ();
1130 /* Print the replacement text. REPLACE also covers
1131 removals, so only do this extra work (potentially starting
1132 a new line) if we have actual replacement text. */
1133 if (replace
->get_length () > 0)
1135 move_to_column (&column
, start_column
);
1136 m_colorizer
.set_fixit_hint ();
1137 pp_string (m_pp
, replace
->get_string ());
1138 m_colorizer
.set_normal_text ();
1139 column
+= replace
->get_length ();
1150 /* Add a trailing newline, if necessary. */
1151 move_to_column (&column
, 0);
1154 /* Disable any colorization and emit a newline. */
1157 layout::print_newline ()
1159 m_colorizer
.set_normal_text ();
1163 /* Return true if (ROW/COLUMN) is within a range of the layout.
1164 If it returns true, OUT_STATE is written to, with the
1165 range index, and whether we should draw the caret at
1166 (ROW/COLUMN) (as opposed to an underline). */
1169 layout::get_state_at_point (/* Inputs. */
1170 int row
, int column
,
1171 int first_non_ws
, int last_non_ws
,
1173 point_state
*out_state
)
1175 layout_range
*range
;
1177 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1179 if (range
->contains_point (row
, column
))
1181 out_state
->range_idx
= i
;
1183 /* Are we at the range's caret? is it visible? */
1184 out_state
->draw_caret_p
= false;
1185 if (range
->m_show_caret_p
1186 && row
== range
->m_caret
.m_line
1187 && column
== range
->m_caret
.m_column
)
1188 out_state
->draw_caret_p
= true;
1190 /* Within a multiline range, don't display any underline
1191 in any leading or trailing whitespace on a line.
1192 We do display carets, however. */
1193 if (!out_state
->draw_caret_p
)
1194 if (column
< first_non_ws
|| column
> last_non_ws
)
1197 /* We are within a range. */
1205 /* Helper function for use by layout::print_line when printing the
1206 annotation line under the source line.
1207 Get the column beyond the rightmost one that could contain a caret or
1208 range marker, given that we stop rendering at trailing whitespace.
1209 ROW is the source line within the given file.
1210 CARET_COLUMN is the column of range 0's caret.
1211 LAST_NON_WS_COLUMN is the last column containing a non-whitespace
1212 character of source (as determined when printing the source line). */
1215 layout::get_x_bound_for_row (int row
, int caret_column
,
1216 int last_non_ws_column
)
1218 int result
= caret_column
+ 1;
1220 layout_range
*range
;
1222 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1224 if (row
>= range
->m_start
.m_line
)
1226 if (range
->m_finish
.m_line
== row
)
1228 /* On the final line within a range; ensure that
1229 we render up to the end of the range. */
1230 if (result
<= range
->m_finish
.m_column
)
1231 result
= range
->m_finish
.m_column
+ 1;
1233 else if (row
< range
->m_finish
.m_line
)
1235 /* Within a multiline range; ensure that we render up to the
1236 last non-whitespace column. */
1237 if (result
<= last_non_ws_column
)
1238 result
= last_non_ws_column
+ 1;
1246 /* Given *COLUMN as an x-coordinate, print spaces to position
1247 successive output at DEST_COLUMN, printing a newline if necessary,
1248 and updating *COLUMN. */
1251 layout::move_to_column (int *column
, int dest_column
)
1253 /* Start a new line if we need to. */
1254 if (*column
> dest_column
)
1260 while (*column
< dest_column
)
1267 /* For debugging layout issues, render a ruler giving column numbers
1268 (after the 1-column indent). */
1271 layout::show_ruler (int max_column
) const
1274 if (max_column
> 99)
1277 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
1278 if (0 == column
% 10)
1279 pp_character (m_pp
, '0' + (column
/ 100) % 10);
1287 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
1288 if (0 == column
% 10)
1289 pp_character (m_pp
, '0' + (column
/ 10) % 10);
1296 for (int column
= 1 + m_x_offset
; column
<= max_column
; column
++)
1297 pp_character (m_pp
, '0' + (column
% 10));
1301 } /* End of anonymous namespace. */
1303 /* Print the physical source code corresponding to the location of
1304 this diagnostic, with additional annotations. */
1307 diagnostic_show_locus (diagnostic_context
* context
,
1308 rich_location
*richloc
,
1309 diagnostic_t diagnostic_kind
)
1311 pp_newline (context
->printer
);
1313 location_t loc
= richloc
->get_loc ();
1314 /* Do nothing if source-printing has been disabled. */
1315 if (!context
->show_caret
)
1318 /* Don't attempt to print source for UNKNOWN_LOCATION and for builtins. */
1319 if (loc
<= BUILTINS_LOCATION
)
1322 /* Don't print the same source location twice in a row, unless we have
1324 if (loc
== context
->last_location
1325 && richloc
->get_num_fixit_hints () == 0)
1328 context
->last_location
= loc
;
1330 const char *saved_prefix
= pp_get_prefix (context
->printer
);
1331 pp_set_prefix (context
->printer
, NULL
);
1333 layout
layout (context
, richloc
, diagnostic_kind
);
1334 for (int line_span_idx
= 0; line_span_idx
< layout
.get_num_line_spans ();
1337 const line_span
*line_span
= layout
.get_line_span (line_span_idx
);
1338 if (layout
.print_heading_for_line_span_index_p (line_span_idx
))
1340 expanded_location exploc
= layout
.get_expanded_location (line_span
);
1341 context
->start_span (context
, exploc
);
1343 int last_line
= line_span
->get_last_line ();
1344 for (int row
= line_span
->get_first_line (); row
<= last_line
; row
++)
1346 /* Print the source line, followed by an annotation line
1347 consisting of any caret/underlines, then any fixits.
1348 If the source line can't be read, print nothing. */
1349 line_bounds lbounds
;
1350 if (layout
.print_source_line (row
, &lbounds
))
1352 layout
.print_annotation_line (row
, lbounds
);
1353 layout
.print_any_fixits (row
, richloc
);
1358 pp_set_prefix (context
->printer
, saved_prefix
);
1363 namespace selftest
{
1365 /* Selftests for diagnostic_show_locus. */
1367 /* Convenience subclass of diagnostic_context for testing
1368 diagnostic_show_locus. */
1370 class test_diagnostic_context
: public diagnostic_context
1373 test_diagnostic_context ()
1375 diagnostic_initialize (this, 0);
1378 ~test_diagnostic_context ()
1380 diagnostic_finish (this);
1384 /* Verify that diagnostic_show_locus works sanely on UNKNOWN_LOCATION. */
1387 test_diagnostic_show_locus_unknown_location ()
1389 test_diagnostic_context dc
;
1390 rich_location
richloc (line_table
, UNKNOWN_LOCATION
);
1391 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1392 ASSERT_STREQ ("\n", pp_formatted_text (dc
.printer
));
1395 /* Verify that diagnostic_show_locus works sanely for various
1398 All of these work on the following 1-line source file:
1401 "foo = bar.field;\n"
1402 which is set up by test_diagnostic_show_locus_one_liner and calls
1408 test_one_liner_simple_caret ()
1410 test_diagnostic_context dc
;
1411 location_t caret
= linemap_position_for_column (line_table
, 10);
1412 rich_location
richloc (line_table
, caret
);
1413 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1415 " foo = bar.field;\n"
1417 pp_formatted_text (dc
.printer
));
1420 /* Caret and range. */
1423 test_one_liner_caret_and_range ()
1425 test_diagnostic_context dc
;
1426 location_t caret
= linemap_position_for_column (line_table
, 10);
1427 location_t start
= linemap_position_for_column (line_table
, 7);
1428 location_t finish
= linemap_position_for_column (line_table
, 15);
1429 location_t loc
= make_location (caret
, start
, finish
);
1430 rich_location
richloc (line_table
, loc
);
1431 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1433 " foo = bar.field;\n"
1435 pp_formatted_text (dc
.printer
));
1438 /* Multiple ranges and carets. */
1441 test_one_liner_multiple_carets_and_ranges ()
1443 test_diagnostic_context dc
;
1445 = make_location (linemap_position_for_column (line_table
, 2),
1446 linemap_position_for_column (line_table
, 1),
1447 linemap_position_for_column (line_table
, 3));
1448 dc
.caret_chars
[0] = 'A';
1451 = make_location (linemap_position_for_column (line_table
, 8),
1452 linemap_position_for_column (line_table
, 7),
1453 linemap_position_for_column (line_table
, 9));
1454 dc
.caret_chars
[1] = 'B';
1457 = make_location (linemap_position_for_column (line_table
, 13),
1458 linemap_position_for_column (line_table
, 11),
1459 linemap_position_for_column (line_table
, 15));
1460 dc
.caret_chars
[2] = 'C';
1462 rich_location
richloc (line_table
, foo
);
1463 richloc
.add_range (bar
, true);
1464 richloc
.add_range (field
, true);
1465 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1467 " foo = bar.field;\n"
1469 pp_formatted_text (dc
.printer
));
1472 /* Insertion fix-it hint: adding an "&" to the front of "bar.field". */
1475 test_one_liner_fixit_insert ()
1477 test_diagnostic_context dc
;
1478 location_t caret
= linemap_position_for_column (line_table
, 7);
1479 rich_location
richloc (line_table
, caret
);
1480 richloc
.add_fixit_insert (caret
, "&");
1481 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1483 " foo = bar.field;\n"
1486 pp_formatted_text (dc
.printer
));
1489 /* Removal fix-it hint: removal of the ".field". */
1492 test_one_liner_fixit_remove ()
1494 test_diagnostic_context dc
;
1495 location_t start
= linemap_position_for_column (line_table
, 10);
1496 location_t finish
= linemap_position_for_column (line_table
, 15);
1497 location_t dot
= make_location (start
, start
, finish
);
1498 rich_location
richloc (line_table
, dot
);
1500 range
.m_start
= start
;
1501 range
.m_finish
= finish
;
1502 richloc
.add_fixit_remove (range
);
1503 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1505 " foo = bar.field;\n"
1508 pp_formatted_text (dc
.printer
));
1511 /* Replace fix-it hint: replacing "field" with "m_field". */
1514 test_one_liner_fixit_replace ()
1516 test_diagnostic_context dc
;
1517 location_t start
= linemap_position_for_column (line_table
, 11);
1518 location_t finish
= linemap_position_for_column (line_table
, 15);
1519 location_t field
= make_location (start
, start
, finish
);
1520 rich_location
richloc (line_table
, field
);
1522 range
.m_start
= start
;
1523 range
.m_finish
= finish
;
1524 richloc
.add_fixit_replace (range
, "m_field");
1525 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1527 " foo = bar.field;\n"
1530 pp_formatted_text (dc
.printer
));
1533 /* Replace fix-it hint: replacing "field" with "m_field",
1534 but where the caret was elsewhere. */
1537 test_one_liner_fixit_replace_non_equal_range ()
1539 test_diagnostic_context dc
;
1540 location_t equals
= linemap_position_for_column (line_table
, 5);
1541 location_t start
= linemap_position_for_column (line_table
, 11);
1542 location_t finish
= linemap_position_for_column (line_table
, 15);
1543 rich_location
richloc (line_table
, equals
);
1545 range
.m_start
= start
;
1546 range
.m_finish
= finish
;
1547 richloc
.add_fixit_replace (range
, "m_field");
1548 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1549 /* The replacement range is not indicated in the annotation line, so
1550 it should be indicated via an additional underline. */
1552 " foo = bar.field;\n"
1556 pp_formatted_text (dc
.printer
));
1559 /* Replace fix-it hint: replacing "field" with "m_field",
1560 where the caret was elsewhere, but where a secondary range
1561 exactly covers "field". */
1564 test_one_liner_fixit_replace_equal_secondary_range ()
1566 test_diagnostic_context dc
;
1567 location_t equals
= linemap_position_for_column (line_table
, 5);
1568 location_t start
= linemap_position_for_column (line_table
, 11);
1569 location_t finish
= linemap_position_for_column (line_table
, 15);
1570 rich_location
richloc (line_table
, equals
);
1571 location_t field
= make_location (start
, start
, finish
);
1572 richloc
.add_range (field
, false);
1574 range
.m_start
= start
;
1575 range
.m_finish
= finish
;
1576 richloc
.add_fixit_replace (range
, "m_field");
1577 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
1578 /* The replacement range is indicated in the annotation line,
1579 so it shouldn't be indicated via an additional underline. */
1581 " foo = bar.field;\n"
1584 pp_formatted_text (dc
.printer
));
1587 /* Run the various one-liner tests. */
1590 test_diagnostic_show_locus_one_liner (const line_table_case
&case_
)
1592 /* Create a tempfile and write some text to it.
1593 ....................0000000001111111.
1594 ....................1234567890123456. */
1595 const char *content
= "foo = bar.field;\n";
1596 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
1597 line_table_test
ltt (case_
);
1599 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 1);
1601 location_t line_end
= linemap_position_for_column (line_table
, 16);
1603 /* Don't attempt to run the tests if column data might be unavailable. */
1604 if (line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
1607 ASSERT_STREQ (tmp
.get_filename (), LOCATION_FILE (line_end
));
1608 ASSERT_EQ (1, LOCATION_LINE (line_end
));
1609 ASSERT_EQ (16, LOCATION_COLUMN (line_end
));
1611 test_one_liner_simple_caret ();
1612 test_one_liner_caret_and_range ();
1613 test_one_liner_multiple_carets_and_ranges ();
1614 test_one_liner_fixit_insert ();
1615 test_one_liner_fixit_remove ();
1616 test_one_liner_fixit_replace ();
1617 test_one_liner_fixit_replace_non_equal_range ();
1618 test_one_liner_fixit_replace_equal_secondary_range ();
1621 /* Run all of the selftests within this file. */
1624 diagnostic_show_locus_c_tests ()
1626 test_range_contains_point_for_single_point ();
1627 test_range_contains_point_for_single_line ();
1628 test_range_contains_point_for_multiple_lines ();
1630 test_get_line_width_without_trailing_whitespace ();
1632 test_diagnostic_show_locus_unknown_location ();
1634 for_each_line_table_case (test_diagnostic_show_locus_one_liner
);
1637 } // namespace selftest
1639 #endif /* #if CHECKING_P */