1 /* Diagnostic subroutines for printing source-code
2 Copyright (C) 1999-2019 Free Software Foundation, Inc.
3 Contributed by Gabriel Dos Reis <gdr@codesourcery.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
27 #include "backtrace.h"
28 #include "diagnostic.h"
29 #include "diagnostic-color.h"
30 #include "gcc-rich-location.h"
32 #include "selftest-diagnostic.h"
39 #ifdef GWINSZ_IN_SYS_IOCTL
40 # include <sys/ioctl.h>
43 /* Disable warnings about quoting issues in the pp_xxx calls below
44 that (intentionally) don't follow GCC diagnostic conventions. */
46 # pragma GCC diagnostic push
47 # pragma GCC diagnostic ignored "-Wformat-diag"
50 /* Classes for rendering source code and diagnostics, within an
52 The work is done by "class layout", which embeds and uses
53 "class colorizer" and "class layout_range" to get things done. */
57 /* The state at a given point of the source code, assuming that we're
58 in a range: which range are we in, and whether we should draw a caret at
67 /* A class to inject colorization codes when printing the diagnostic locus.
69 It has one kind of colorization for each of:
71 - range 0 (the "primary location")
75 The class caches the lookup of the color codes for the above.
77 The class also has responsibility for tracking which of the above is
78 active, filtering out unnecessary changes. This allows
79 layout::print_source_line and layout::print_annotation_line
80 to simply request a colorization code for *every* character they print,
81 via this class, and have the filtering be done for them here. */
86 colorizer (diagnostic_context
*context
,
87 diagnostic_t diagnostic_kind
);
90 void set_range (int range_idx
) { set_state (range_idx
); }
91 void set_normal_text () { set_state (STATE_NORMAL_TEXT
); }
92 void set_fixit_insert () { set_state (STATE_FIXIT_INSERT
); }
93 void set_fixit_delete () { set_state (STATE_FIXIT_DELETE
); }
96 void set_state (int state
);
97 void begin_state (int state
);
98 void finish_state (int state
);
99 const char *get_color_by_name (const char *);
102 static const int STATE_NORMAL_TEXT
= -1;
103 static const int STATE_FIXIT_INSERT
= -2;
104 static const int STATE_FIXIT_DELETE
= -3;
106 diagnostic_context
*m_context
;
107 diagnostic_t m_diagnostic_kind
;
109 const char *m_range1
;
110 const char *m_range2
;
111 const char *m_fixit_insert
;
112 const char *m_fixit_delete
;
113 const char *m_stop_color
;
116 /* In order to handle multibyte sources properly, all of this logic needs to be
117 aware of the distinction between the number of bytes and the number of
118 display columns occupied by a character, which are not the same for non-ASCII
119 characters. For example, the Unicode pi symbol, U+03C0, is encoded in UTF-8
120 as "\xcf\x80", and thus occupies 2 bytes of space while only occupying 1
121 display column when it is output. A typical emoji, such as U+1F602 (in
122 UTF-8, "\xf0\x9f\x98\x82"), requires 4 bytes and has a display width of 2.
124 The below example line, which is also used for selftests below, shows how the
125 display column and byte column are related:
127 0000000001111111111222222 display
128 1234567890123456789012345 columns
129 SS_foo = P_bar.SS_fieldP;
130 0000000111111111222222223 byte
131 1356789012456789134567891 columns
133 Here SS represents the two display columns for the U+1F602 emoji, and P
134 represents the one display column for the U+03C0 pi symbol. As an example, a
135 diagnostic pointing to the final P on this line is at byte column 29 and
136 display column 24. This reflects the fact that the three extended characters
137 before the final P occupy cumulatively 5 more bytes than they do display
138 columns (a difference of 2 for each of the two SSs, and one for the other P).
140 One or the other of the two column units is more useful depending on the
141 context. For instance, in order to output the caret at the correct location,
142 we need to count display columns; in order to colorize a source line, we need
143 to count the bytes. All locations are provided to us as byte counts, which
144 we augment with the display column on demand so that it can be used when
145 needed. This is not the most efficient way to do things since it requires
146 looping over the whole line each time, but it should be fine for the purpose
147 of outputting diagnostics.
149 In order to keep straight which units (byte or display) are in use at a
150 given time, the following enum lets us specify that explicitly. */
153 /* Measured in raw bytes. */
156 /* Measured in display units. */
159 /* For arrays indexed by column_unit. */
163 /* Utility class to augment an exploc with the corresponding display column. */
165 class exploc_with_display_col
: public expanded_location
168 exploc_with_display_col (const expanded_location
&exploc
)
169 : expanded_location (exploc
),
170 m_display_col (location_compute_display_column (exploc
)) {}
176 /* A point within a layout_range; similar to an exploc_with_display_col,
177 but after filtering on file. */
182 layout_point (const expanded_location
&exploc
)
183 : m_line (exploc
.line
)
185 m_columns
[CU_BYTES
] = exploc
.column
;
186 m_columns
[CU_DISPLAY_COLS
] = location_compute_display_column (exploc
);
190 int m_columns
[CU_NUM_UNITS
];
193 /* A class for use by "class layout" below: a filtered location_range. */
198 layout_range (const expanded_location
*start_exploc
,
199 const expanded_location
*finish_exploc
,
200 enum range_display_kind range_display_kind
,
201 const expanded_location
*caret_exploc
,
202 unsigned original_idx
,
203 const range_label
*label
);
205 bool contains_point (linenum_type row
, int column
,
206 enum column_unit col_unit
) const;
207 bool intersects_line_p (linenum_type row
) const;
209 layout_point m_start
;
210 layout_point m_finish
;
211 enum range_display_kind m_range_display_kind
;
212 layout_point m_caret
;
213 unsigned m_original_idx
;
214 const range_label
*m_label
;
217 /* A struct for use by layout::print_source_line for telling
218 layout::print_annotation_line the extents of the source line that
219 it printed, so that underlines can be clipped appropriately. */
226 void convert_to_display_cols (char_span line
)
228 m_first_non_ws
= cpp_byte_column_to_display_column (line
.get_buffer (),
232 m_last_non_ws
= cpp_byte_column_to_display_column (line
.get_buffer (),
238 /* A range of contiguous source lines within a layout (e.g. "lines 5-10"
239 or "line 23"). During the layout ctor, layout::calculate_line_spans
240 splits the pertinent source lines into a list of disjoint line_span
241 instances (e.g. lines 5-10, lines 15-20, line 23). */
246 line_span (linenum_type first_line
, linenum_type last_line
)
247 : m_first_line (first_line
), m_last_line (last_line
)
249 gcc_assert (first_line
<= last_line
);
251 linenum_type
get_first_line () const { return m_first_line
; }
252 linenum_type
get_last_line () const { return m_last_line
; }
254 bool contains_line_p (linenum_type line
) const
256 return line
>= m_first_line
&& line
<= m_last_line
;
259 static int comparator (const void *p1
, const void *p2
)
261 const line_span
*ls1
= (const line_span
*)p1
;
262 const line_span
*ls2
= (const line_span
*)p2
;
263 int first_line_cmp
= compare (ls1
->m_first_line
, ls2
->m_first_line
);
265 return first_line_cmp
;
266 return compare (ls1
->m_last_line
, ls2
->m_last_line
);
269 linenum_type m_first_line
;
270 linenum_type m_last_line
;
275 /* Selftests for line_span. */
280 line_span
line_one (1, 1);
281 ASSERT_EQ (1, line_one
.get_first_line ());
282 ASSERT_EQ (1, line_one
.get_last_line ());
283 ASSERT_FALSE (line_one
.contains_line_p (0));
284 ASSERT_TRUE (line_one
.contains_line_p (1));
285 ASSERT_FALSE (line_one
.contains_line_p (2));
287 line_span
lines_1_to_3 (1, 3);
288 ASSERT_EQ (1, lines_1_to_3
.get_first_line ());
289 ASSERT_EQ (3, lines_1_to_3
.get_last_line ());
290 ASSERT_TRUE (lines_1_to_3
.contains_line_p (1));
291 ASSERT_TRUE (lines_1_to_3
.contains_line_p (3));
293 ASSERT_EQ (0, line_span::comparator (&line_one
, &line_one
));
294 ASSERT_GT (line_span::comparator (&lines_1_to_3
, &line_one
), 0);
295 ASSERT_LT (line_span::comparator (&line_one
, &lines_1_to_3
), 0);
297 /* A linenum > 2^31. */
298 const linenum_type LARGEST_LINE
= 0xffffffff;
299 line_span
largest_line (LARGEST_LINE
, LARGEST_LINE
);
300 ASSERT_EQ (LARGEST_LINE
, largest_line
.get_first_line ());
301 ASSERT_EQ (LARGEST_LINE
, largest_line
.get_last_line ());
303 ASSERT_GT (line_span::comparator (&largest_line
, &line_one
), 0);
304 ASSERT_LT (line_span::comparator (&line_one
, &largest_line
), 0);
307 #endif /* #if CHECKING_P */
309 /* A class to control the overall layout when printing a diagnostic.
311 The layout is determined within the constructor.
312 It is then printed by repeatedly calling the "print_source_line",
313 "print_annotation_line" and "print_any_fixits" methods.
315 We assume we have disjoint ranges. */
320 layout (diagnostic_context
*context
,
321 rich_location
*richloc
,
322 diagnostic_t diagnostic_kind
);
324 bool maybe_add_location_range (const location_range
*loc_range
,
325 unsigned original_idx
,
326 bool restrict_to_current_line_spans
);
328 int get_num_line_spans () const { return m_line_spans
.length (); }
329 const line_span
*get_line_span (int idx
) const { return &m_line_spans
[idx
]; }
331 int get_linenum_width () const { return m_linenum_width
; }
332 int get_x_offset_display () const { return m_x_offset_display
; }
334 void print_gap_in_line_numbering ();
335 bool print_heading_for_line_span_index_p (int line_span_idx
) const;
337 expanded_location
get_expanded_location (const line_span
*) const;
339 void print_line (linenum_type row
);
342 bool will_show_line_p (linenum_type row
) const;
343 void print_leading_fixits (linenum_type row
);
344 void print_source_line (linenum_type row
, const char *line
, int line_bytes
,
345 line_bounds
*lbounds_out
);
346 bool should_print_annotation_line_p (linenum_type row
) const;
347 void start_annotation_line (char margin_char
= ' ') const;
348 void print_annotation_line (linenum_type row
, const line_bounds lbounds
);
349 void print_any_labels (linenum_type row
);
350 void print_trailing_fixits (linenum_type row
);
352 bool annotation_line_showed_range_p (linenum_type line
, int start_column
,
353 int finish_column
) const;
354 void show_ruler (int max_column
) const;
356 bool validate_fixit_hint_p (const fixit_hint
*hint
);
358 void calculate_line_spans ();
359 void calculate_linenum_width ();
360 void calculate_x_offset_display ();
362 void print_newline ();
365 get_state_at_point (/* Inputs. */
366 linenum_type row
, int column
,
367 int first_non_ws
, int last_non_ws
,
368 enum column_unit col_unit
,
370 point_state
*out_state
);
373 get_x_bound_for_row (linenum_type row
, int caret_column
,
377 move_to_column (int *column
, int dest_column
, bool add_left_margin
);
380 diagnostic_context
*m_context
;
381 pretty_printer
*m_pp
;
382 location_t m_primary_loc
;
383 exploc_with_display_col m_exploc
;
384 colorizer m_colorizer
;
385 bool m_colorize_source_p
;
386 bool m_show_labels_p
;
387 bool m_show_line_numbers_p
;
388 auto_vec
<layout_range
> m_layout_ranges
;
389 auto_vec
<const fixit_hint
*> m_fixit_hints
;
390 auto_vec
<line_span
> m_line_spans
;
392 int m_x_offset_display
;
395 /* Implementation of "class colorizer". */
397 /* The constructor for "colorizer". Lookup and store color codes for the
398 different kinds of things we might need to print. */
400 colorizer::colorizer (diagnostic_context
*context
,
401 diagnostic_t diagnostic_kind
) :
403 m_diagnostic_kind (diagnostic_kind
),
404 m_current_state (STATE_NORMAL_TEXT
)
406 m_range1
= get_color_by_name ("range1");
407 m_range2
= get_color_by_name ("range2");
408 m_fixit_insert
= get_color_by_name ("fixit-insert");
409 m_fixit_delete
= get_color_by_name ("fixit-delete");
410 m_stop_color
= colorize_stop (pp_show_color (context
->printer
));
413 /* The destructor for "colorize". If colorization is on, print a code to
416 colorizer::~colorizer ()
418 finish_state (m_current_state
);
421 /* Update state, printing color codes if necessary if there's a state
425 colorizer::set_state (int new_state
)
427 if (m_current_state
!= new_state
)
429 finish_state (m_current_state
);
430 m_current_state
= new_state
;
431 begin_state (new_state
);
435 /* Turn on any colorization for STATE. */
438 colorizer::begin_state (int state
)
442 case STATE_NORMAL_TEXT
:
445 case STATE_FIXIT_INSERT
:
446 pp_string (m_context
->printer
, m_fixit_insert
);
449 case STATE_FIXIT_DELETE
:
450 pp_string (m_context
->printer
, m_fixit_delete
);
454 /* Make range 0 be the same color as the "kind" text
455 (error vs warning vs note). */
458 colorize_start (pp_show_color (m_context
->printer
),
459 diagnostic_get_color_for_kind (m_diagnostic_kind
)));
463 pp_string (m_context
->printer
, m_range1
);
467 pp_string (m_context
->printer
, m_range2
);
471 /* For ranges beyond 2, alternate between color 1 and color 2. */
473 gcc_assert (state
> 2);
474 pp_string (m_context
->printer
,
475 state
% 2 ? m_range1
: m_range2
);
481 /* Turn off any colorization for STATE. */
484 colorizer::finish_state (int state
)
486 if (state
!= STATE_NORMAL_TEXT
)
487 pp_string (m_context
->printer
, m_stop_color
);
490 /* Get the color code for NAME (or the empty string if
491 colorization is disabled). */
494 colorizer::get_color_by_name (const char *name
)
496 return colorize_start (pp_show_color (m_context
->printer
), name
);
499 /* Implementation of class layout_range. */
501 /* The constructor for class layout_range.
502 Initialize various layout_point fields from expanded_location
503 equivalents; we've already filtered on file. */
505 layout_range::layout_range (const expanded_location
*start_exploc
,
506 const expanded_location
*finish_exploc
,
507 enum range_display_kind range_display_kind
,
508 const expanded_location
*caret_exploc
,
509 unsigned original_idx
,
510 const range_label
*label
)
511 : m_start (*start_exploc
),
512 m_finish (*finish_exploc
),
513 m_range_display_kind (range_display_kind
),
514 m_caret (*caret_exploc
),
515 m_original_idx (original_idx
),
520 /* Is (column, row) within the given range?
521 We've already filtered on the file.
523 Ranges are closed (both limits are within the range).
525 Example A: a single-line range:
526 start: (col=22, line=2)
527 finish: (col=38, line=2)
529 |00000011111111112222222222333333333344444444444
530 |34567890123456789012345678901234567890123456789
531 --+-----------------------------------------------
532 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
533 02|bbbbbbbbbbbbbbbbbbbSwwwwwwwwwwwwwwwFaaaaaaaaaaa
534 03|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
536 Example B: a multiline range with
537 start: (col=14, line=3)
538 finish: (col=08, line=5)
540 |00000011111111112222222222333333333344444444444
541 |34567890123456789012345678901234567890123456789
542 --+-----------------------------------------------
543 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
544 02|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
545 03|bbbbbbbbbbbSwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
546 04|wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
547 05|wwwwwFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
548 06|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
549 --+-----------------------------------------------
552 - 'b' indicates a point *before* the range
553 - 'S' indicates the start of the range
554 - 'w' indicates a point within the range
555 - 'F' indicates the finish of the range (which is
557 - 'a' indicates a subsequent point *after* the range.
559 COL_UNIT controls whether we check the byte column or
560 the display column; one or the other is more convenient
561 depending on the context. */
564 layout_range::contains_point (linenum_type row
, int column
,
565 enum column_unit col_unit
) const
567 gcc_assert (m_start
.m_line
<= m_finish
.m_line
);
568 /* ...but the equivalent isn't true for the columns;
569 consider example B in the comment above. */
571 if (row
< m_start
.m_line
)
572 /* Points before the first line of the range are
573 outside it (corresponding to line 01 in example A
574 and lines 01 and 02 in example B above). */
577 if (row
== m_start
.m_line
)
578 /* On same line as start of range (corresponding
579 to line 02 in example A and line 03 in example B). */
581 if (column
< m_start
.m_columns
[col_unit
])
582 /* Points on the starting line of the range, but
583 before the column in which it begins. */
586 if (row
< m_finish
.m_line
)
587 /* This is a multiline range; the point
588 is within it (corresponds to line 03 in example B
589 from column 14 onwards) */
593 /* This is a single-line range. */
594 gcc_assert (row
== m_finish
.m_line
);
595 return column
<= m_finish
.m_columns
[col_unit
];
599 /* The point is in a line beyond that containing the
600 start of the range: lines 03 onwards in example A,
601 and lines 04 onwards in example B. */
602 gcc_assert (row
> m_start
.m_line
);
604 if (row
> m_finish
.m_line
)
605 /* The point is beyond the final line of the range
606 (lines 03 onwards in example A, and lines 06 onwards
610 if (row
< m_finish
.m_line
)
612 /* The point is in a line that's fully within a multiline
613 range (e.g. line 04 in example B). */
614 gcc_assert (m_start
.m_line
< m_finish
.m_line
);
618 gcc_assert (row
== m_finish
.m_line
);
620 return column
<= m_finish
.m_columns
[col_unit
];
623 /* Does this layout_range contain any part of line ROW? */
626 layout_range::intersects_line_p (linenum_type row
) const
628 gcc_assert (m_start
.m_line
<= m_finish
.m_line
);
629 if (row
< m_start
.m_line
)
631 if (row
> m_finish
.m_line
)
638 /* Create some expanded locations for testing layout_range. The filename
639 member of the explocs is set to the empty string. This member will only be
640 inspected by the calls to location_compute_display_column() made from the
641 layout_point constructors. That function will check for an empty filename
642 argument and not attempt to open it, rather treating the non-existent data
643 as if the display width were the same as the byte count. Tests exercising a
644 real difference between byte count and display width are performed later,
645 e.g. in test_diagnostic_show_locus_one_liner_utf8(). */
648 make_range (int start_line
, int start_col
, int end_line
, int end_col
)
650 const expanded_location start_exploc
651 = {"", start_line
, start_col
, NULL
, false};
652 const expanded_location finish_exploc
653 = {"", end_line
, end_col
, NULL
, false};
654 return layout_range (&start_exploc
, &finish_exploc
, SHOW_RANGE_WITHOUT_CARET
,
655 &start_exploc
, 0, NULL
);
658 /* Selftests for layout_range::contains_point and
659 layout_range::intersects_line_p. */
661 /* Selftest for layout_range, where the layout_range
662 is a range with start==end i.e. a single point. */
665 test_layout_range_for_single_point ()
667 layout_range point
= make_range (7, 10, 7, 10);
669 /* Tests for layout_range::contains_point. */
671 for (int i
= 0; i
!= CU_NUM_UNITS
; ++i
)
673 const enum column_unit col_unit
= (enum column_unit
) i
;
675 /* Before the line. */
676 ASSERT_FALSE (point
.contains_point (6, 1, col_unit
));
678 /* On the line, but before start. */
679 ASSERT_FALSE (point
.contains_point (7, 9, col_unit
));
682 ASSERT_TRUE (point
.contains_point (7, 10, col_unit
));
684 /* On the line, after the point. */
685 ASSERT_FALSE (point
.contains_point (7, 11, col_unit
));
687 /* After the line. */
688 ASSERT_FALSE (point
.contains_point (8, 1, col_unit
));
691 /* Tests for layout_range::intersects_line_p. */
692 ASSERT_FALSE (point
.intersects_line_p (6));
693 ASSERT_TRUE (point
.intersects_line_p (7));
694 ASSERT_FALSE (point
.intersects_line_p (8));
697 /* Selftest for layout_range, where the layout_range
698 is the single-line range shown as "Example A" above. */
701 test_layout_range_for_single_line ()
703 layout_range example_a
= make_range (2, 22, 2, 38);
705 /* Tests for layout_range::contains_point. */
707 for (int i
= 0; i
!= CU_NUM_UNITS
; ++i
)
709 const enum column_unit col_unit
= (enum column_unit
) i
;
711 /* Before the line. */
712 ASSERT_FALSE (example_a
.contains_point (1, 1, col_unit
));
714 /* On the line, but before start. */
715 ASSERT_FALSE (example_a
.contains_point (2, 21, col_unit
));
717 /* On the line, at the start. */
718 ASSERT_TRUE (example_a
.contains_point (2, 22, col_unit
));
720 /* On the line, within the range. */
721 ASSERT_TRUE (example_a
.contains_point (2, 23, col_unit
));
723 /* On the line, at the end. */
724 ASSERT_TRUE (example_a
.contains_point (2, 38, col_unit
));
726 /* On the line, after the end. */
727 ASSERT_FALSE (example_a
.contains_point (2, 39, col_unit
));
729 /* After the line. */
730 ASSERT_FALSE (example_a
.contains_point (2, 39, col_unit
));
733 /* Tests for layout_range::intersects_line_p. */
734 ASSERT_FALSE (example_a
.intersects_line_p (1));
735 ASSERT_TRUE (example_a
.intersects_line_p (2));
736 ASSERT_FALSE (example_a
.intersects_line_p (3));
739 /* Selftest for layout_range, where the layout_range
740 is the multi-line range shown as "Example B" above. */
743 test_layout_range_for_multiple_lines ()
745 layout_range example_b
= make_range (3, 14, 5, 8);
747 /* Tests for layout_range::contains_point. */
749 for (int i
= 0; i
!= CU_NUM_UNITS
; ++i
)
751 const enum column_unit col_unit
= (enum column_unit
) i
;
753 /* Before first line. */
754 ASSERT_FALSE (example_b
.contains_point (1, 1, col_unit
));
756 /* On the first line, but before start. */
757 ASSERT_FALSE (example_b
.contains_point (3, 13, col_unit
));
760 ASSERT_TRUE (example_b
.contains_point (3, 14, col_unit
));
762 /* On the first line, within the range. */
763 ASSERT_TRUE (example_b
.contains_point (3, 15, col_unit
));
765 /* On an interior line.
766 The column number should not matter; try various boundary
768 ASSERT_TRUE (example_b
.contains_point (4, 1, col_unit
));
769 ASSERT_TRUE (example_b
.contains_point (4, 7, col_unit
));
770 ASSERT_TRUE (example_b
.contains_point (4, 8, col_unit
));
771 ASSERT_TRUE (example_b
.contains_point (4, 9, col_unit
));
772 ASSERT_TRUE (example_b
.contains_point (4, 13, col_unit
));
773 ASSERT_TRUE (example_b
.contains_point (4, 14, col_unit
));
774 ASSERT_TRUE (example_b
.contains_point (4, 15, col_unit
));
776 /* On the final line, before the end. */
777 ASSERT_TRUE (example_b
.contains_point (5, 7, col_unit
));
779 /* On the final line, at the end. */
780 ASSERT_TRUE (example_b
.contains_point (5, 8, col_unit
));
782 /* On the final line, after the end. */
783 ASSERT_FALSE (example_b
.contains_point (5, 9, col_unit
));
785 /* After the line. */
786 ASSERT_FALSE (example_b
.contains_point (6, 1, col_unit
));
789 /* Tests for layout_range::intersects_line_p. */
790 ASSERT_FALSE (example_b
.intersects_line_p (2));
791 ASSERT_TRUE (example_b
.intersects_line_p (3));
792 ASSERT_TRUE (example_b
.intersects_line_p (4));
793 ASSERT_TRUE (example_b
.intersects_line_p (5));
794 ASSERT_FALSE (example_b
.intersects_line_p (6));
797 #endif /* #if CHECKING_P */
799 /* Given a source line LINE of length LINE_BYTES bytes, determine the length
800 (still in bytes, not display cols) without any trailing whitespace. */
803 get_line_bytes_without_trailing_whitespace (const char *line
, int line_bytes
)
805 int result
= line_bytes
;
808 char ch
= line
[result
- 1];
809 if (ch
== ' ' || ch
== '\t' || ch
== '\r')
814 gcc_assert (result
>= 0);
815 gcc_assert (result
<= line_bytes
);
816 gcc_assert (result
== 0 ||
817 (line
[result
- 1] != ' '
818 && line
[result
-1] != '\t'
819 && line
[result
-1] != '\r'));
825 /* A helper function for testing get_line_bytes_without_trailing_whitespace. */
828 assert_eq (const char *line
, int expected_bytes
)
831 = get_line_bytes_without_trailing_whitespace (line
, strlen (line
));
832 ASSERT_EQ (actual_value
, expected_bytes
);
835 /* Verify that get_line_bytes_without_trailing_whitespace is sane for
836 various inputs. It is not required to handle newlines. */
839 test_get_line_bytes_without_trailing_whitespace ()
845 assert_eq ("hello world", 11);
846 assert_eq ("hello world ", 11);
847 assert_eq ("hello world \t\t ", 11);
848 assert_eq ("hello world\r", 11);
851 #endif /* #if CHECKING_P */
853 /* Helper function for layout's ctor, for sanitizing locations relative
854 to the primary location within a diagnostic.
856 Compare LOC_A and LOC_B to see if it makes sense to print underlines
857 connecting their expanded locations. Doing so is only guaranteed to
858 make sense if the locations share the same macro expansion "history"
859 i.e. they can be traced through the same macro expansions, eventually
860 reaching an ordinary map.
862 This may be too strong a condition, but it effectively sanitizes
863 PR c++/70105, which has an example of printing an expression where the
864 final location of the expression is in a different macro, which
865 erroneously was leading to hundreds of lines of irrelevant source
869 compatible_locations_p (location_t loc_a
, location_t loc_b
)
871 if (IS_ADHOC_LOC (loc_a
))
872 loc_a
= get_location_from_adhoc_loc (line_table
, loc_a
);
873 if (IS_ADHOC_LOC (loc_b
))
874 loc_b
= get_location_from_adhoc_loc (line_table
, loc_b
);
876 /* If either location is one of the special locations outside of a
877 linemap, they are only compatible if they are equal. */
878 if (loc_a
< RESERVED_LOCATION_COUNT
879 || loc_b
< RESERVED_LOCATION_COUNT
)
880 return loc_a
== loc_b
;
882 const line_map
*map_a
= linemap_lookup (line_table
, loc_a
);
883 linemap_assert (map_a
);
885 const line_map
*map_b
= linemap_lookup (line_table
, loc_b
);
886 linemap_assert (map_b
);
888 /* Are they within the same map? */
891 /* Are both within the same macro expansion? */
892 if (linemap_macro_expansion_map_p (map_a
))
894 /* Expand each location towards the spelling location, and
896 const line_map_macro
*macro_map
= linemap_check_macro (map_a
);
897 location_t loc_a_toward_spelling
898 = linemap_macro_map_loc_unwind_toward_spelling (line_table
,
901 location_t loc_b_toward_spelling
902 = linemap_macro_map_loc_unwind_toward_spelling (line_table
,
905 return compatible_locations_p (loc_a_toward_spelling
,
906 loc_b_toward_spelling
);
909 /* Otherwise they are within the same ordinary map. */
914 /* Within different maps. */
916 /* If either is within a macro expansion, they are incompatible. */
917 if (linemap_macro_expansion_map_p (map_a
)
918 || linemap_macro_expansion_map_p (map_b
))
921 /* Within two different ordinary maps; they are compatible iff they
922 are in the same file. */
923 const line_map_ordinary
*ord_map_a
= linemap_check_ordinary (map_a
);
924 const line_map_ordinary
*ord_map_b
= linemap_check_ordinary (map_b
);
925 return ord_map_a
->to_file
== ord_map_b
->to_file
;
929 /* Comparator for sorting fix-it hints. */
932 fixit_cmp (const void *p_a
, const void *p_b
)
934 const fixit_hint
* hint_a
= *static_cast<const fixit_hint
* const *> (p_a
);
935 const fixit_hint
* hint_b
= *static_cast<const fixit_hint
* const *> (p_b
);
936 return hint_a
->get_start_loc () - hint_b
->get_start_loc ();
939 /* Implementation of class layout. */
941 /* Constructor for class layout.
943 Filter the ranges from the rich_location to those that we can
944 sanely print, populating m_layout_ranges and m_fixit_hints.
945 Determine the range of lines that we will print, splitting them
946 up into an ordered list of disjoint spans of contiguous line numbers.
947 Determine m_x_offset_display, to ensure that the primary caret
948 will fit within the max_width provided by the diagnostic_context. */
950 layout::layout (diagnostic_context
* context
,
951 rich_location
*richloc
,
952 diagnostic_t diagnostic_kind
)
953 : m_context (context
),
954 m_pp (context
->printer
),
955 m_primary_loc (richloc
->get_range (0)->m_loc
),
956 m_exploc (richloc
->get_expanded_location (0)),
957 m_colorizer (context
, diagnostic_kind
),
958 m_colorize_source_p (context
->colorize_source_p
),
959 m_show_labels_p (context
->show_labels_p
),
960 m_show_line_numbers_p (context
->show_line_numbers_p
),
961 m_layout_ranges (richloc
->get_num_locations ()),
962 m_fixit_hints (richloc
->get_num_fixit_hints ()),
963 m_line_spans (1 + richloc
->get_num_locations ()),
965 m_x_offset_display (0)
967 for (unsigned int idx
= 0; idx
< richloc
->get_num_locations (); idx
++)
969 /* This diagnostic printer can only cope with "sufficiently sane" ranges.
970 Ignore any ranges that are awkward to handle. */
971 const location_range
*loc_range
= richloc
->get_range (idx
);
972 maybe_add_location_range (loc_range
, idx
, false);
975 /* Populate m_fixit_hints, filtering to only those that are in the
977 for (unsigned int i
= 0; i
< richloc
->get_num_fixit_hints (); i
++)
979 const fixit_hint
*hint
= richloc
->get_fixit_hint (i
);
980 if (validate_fixit_hint_p (hint
))
981 m_fixit_hints
.safe_push (hint
);
984 /* Sort m_fixit_hints. */
985 m_fixit_hints
.qsort (fixit_cmp
);
987 /* Populate the indicated members. */
988 calculate_line_spans ();
989 calculate_linenum_width ();
990 calculate_x_offset_display ();
992 if (context
->show_ruler_p
)
993 show_ruler (m_x_offset_display
+ m_context
->caret_max_width
);
997 /* Attempt to add LOC_RANGE to m_layout_ranges, filtering them to
998 those that we can sanely print.
1000 ORIGINAL_IDX is the index of LOC_RANGE within its rich_location,
1001 (for use as extrinsic state by label ranges FIXME).
1003 If RESTRICT_TO_CURRENT_LINE_SPANS is true, then LOC_RANGE is also
1004 filtered against this layout instance's current line spans: it
1005 will only be added if the location is fully within the lines
1006 already specified by other locations.
1008 Return true iff LOC_RANGE was added. */
1011 layout::maybe_add_location_range (const location_range
*loc_range
,
1012 unsigned original_idx
,
1013 bool restrict_to_current_line_spans
)
1015 gcc_assert (loc_range
);
1017 /* Split the "range" into caret and range information. */
1018 source_range src_range
= get_range_from_loc (line_table
, loc_range
->m_loc
);
1020 /* Expand the various locations. */
1021 expanded_location start
1022 = linemap_client_expand_location_to_spelling_point
1023 (src_range
.m_start
, LOCATION_ASPECT_START
);
1024 expanded_location finish
1025 = linemap_client_expand_location_to_spelling_point
1026 (src_range
.m_finish
, LOCATION_ASPECT_FINISH
);
1027 expanded_location caret
1028 = linemap_client_expand_location_to_spelling_point
1029 (loc_range
->m_loc
, LOCATION_ASPECT_CARET
);
1031 /* If any part of the range isn't in the same file as the primary
1032 location of this diagnostic, ignore the range. */
1033 if (start
.file
!= m_exploc
.file
)
1035 if (finish
.file
!= m_exploc
.file
)
1037 if (loc_range
->m_range_display_kind
== SHOW_RANGE_WITH_CARET
)
1038 if (caret
.file
!= m_exploc
.file
)
1041 /* Sanitize the caret location for non-primary ranges. */
1042 if (m_layout_ranges
.length () > 0)
1043 if (loc_range
->m_range_display_kind
== SHOW_RANGE_WITH_CARET
)
1044 if (!compatible_locations_p (loc_range
->m_loc
, m_primary_loc
))
1045 /* Discard any non-primary ranges that can't be printed
1046 sanely relative to the primary location. */
1049 /* Everything is now known to be in the correct source file,
1050 but it may require further sanitization. */
1051 layout_range
ri (&start
, &finish
, loc_range
->m_range_display_kind
, &caret
,
1052 original_idx
, loc_range
->m_label
);
1054 /* If we have a range that finishes before it starts (perhaps
1055 from something built via macro expansion), printing the
1056 range is likely to be nonsensical. Also, attempting to do so
1057 breaks assumptions within the printing code (PR c/68473).
1058 Similarly, don't attempt to print ranges if one or both ends
1059 of the range aren't sane to print relative to the
1060 primary location (PR c++/70105). */
1061 if (start
.line
> finish
.line
1062 || !compatible_locations_p (src_range
.m_start
, m_primary_loc
)
1063 || !compatible_locations_p (src_range
.m_finish
, m_primary_loc
))
1065 /* Is this the primary location? */
1066 if (m_layout_ranges
.length () == 0)
1068 /* We want to print the caret for the primary location, but
1069 we must sanitize away m_start and m_finish. */
1070 ri
.m_start
= ri
.m_caret
;
1071 ri
.m_finish
= ri
.m_caret
;
1074 /* This is a non-primary range; ignore it. */
1078 /* Potentially filter to just the lines already specified by other
1079 locations. This is for use by gcc_rich_location::add_location_if_nearby.
1080 The layout ctor doesn't use it, and can't because m_line_spans
1081 hasn't been set up at that point. */
1082 if (restrict_to_current_line_spans
)
1084 if (!will_show_line_p (start
.line
))
1086 if (!will_show_line_p (finish
.line
))
1088 if (loc_range
->m_range_display_kind
== SHOW_RANGE_WITH_CARET
)
1089 if (!will_show_line_p (caret
.line
))
1093 /* Passed all the tests; add the range to m_layout_ranges so that
1094 it will be printed. */
1095 m_layout_ranges
.safe_push (ri
);
1099 /* Return true iff ROW is within one of the line spans for this layout. */
1102 layout::will_show_line_p (linenum_type row
) const
1104 for (int line_span_idx
= 0; line_span_idx
< get_num_line_spans ();
1107 const line_span
*line_span
= get_line_span (line_span_idx
);
1108 if (line_span
->contains_line_p (row
))
1114 /* Print a line showing a gap in the line numbers, for showing the boundary
1115 between two line spans. */
1118 layout::print_gap_in_line_numbering ()
1120 gcc_assert (m_show_line_numbers_p
);
1122 pp_emit_prefix (m_pp
);
1124 for (int i
= 0; i
< m_linenum_width
+ 1; i
++)
1125 pp_character (m_pp
, '.');
1130 /* Return true iff we should print a heading when starting the
1131 line span with the given index. */
1134 layout::print_heading_for_line_span_index_p (int line_span_idx
) const
1136 /* We print a heading for every change of line span, hence for every
1137 line span after the initial one. */
1138 if (line_span_idx
> 0)
1141 /* We also do it for the initial span if the primary location of the
1142 diagnostic is in a different span. */
1143 if (m_exploc
.line
> (int)get_line_span (0)->m_last_line
)
1149 /* Get an expanded_location for the first location of interest within
1150 the given line_span.
1151 Used when printing a heading to indicate a new line span. */
1154 layout::get_expanded_location (const line_span
*line_span
) const
1156 /* Whenever possible, use the caret location. */
1157 if (line_span
->contains_line_p (m_exploc
.line
))
1160 /* Otherwise, use the start of the first range that's present
1161 within the line_span. */
1162 for (unsigned int i
= 0; i
< m_layout_ranges
.length (); i
++)
1164 const layout_range
*lr
= &m_layout_ranges
[i
];
1165 if (line_span
->contains_line_p (lr
->m_start
.m_line
))
1167 expanded_location exploc
= m_exploc
;
1168 exploc
.line
= lr
->m_start
.m_line
;
1169 exploc
.column
= lr
->m_start
.m_columns
[CU_BYTES
];
1174 /* Otherwise, use the location of the first fixit-hint present within
1176 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1178 const fixit_hint
*hint
= m_fixit_hints
[i
];
1179 location_t loc
= hint
->get_start_loc ();
1180 expanded_location exploc
= expand_location (loc
);
1181 if (line_span
->contains_line_p (exploc
.line
))
1185 /* It should not be possible to have a line span that didn't
1186 contain any of the layout_range or fixit_hint instances. */
1191 /* Determine if HINT is meaningful to print within this layout. */
1194 layout::validate_fixit_hint_p (const fixit_hint
*hint
)
1196 if (LOCATION_FILE (hint
->get_start_loc ()) != m_exploc
.file
)
1198 if (LOCATION_FILE (hint
->get_next_loc ()) != m_exploc
.file
)
1204 /* Determine the range of lines affected by HINT.
1205 This assumes that HINT has already been filtered by
1206 validate_fixit_hint_p, and so affects the correct source file. */
1209 get_line_span_for_fixit_hint (const fixit_hint
*hint
)
1213 int start_line
= LOCATION_LINE (hint
->get_start_loc ());
1215 /* For line-insertion fix-it hints, add the previous line to the
1216 span, to give the user more context on the proposed change. */
1217 if (hint
->ends_with_newline_p ())
1221 return line_span (start_line
,
1222 LOCATION_LINE (hint
->get_next_loc ()));
1225 /* We want to print the pertinent source code at a diagnostic. The
1226 rich_location can contain multiple locations. This will have been
1227 filtered into m_exploc (the caret for the primary location) and
1228 m_layout_ranges, for those ranges within the same source file.
1230 We will print a subset of the lines within the source file in question,
1231 as a collection of "spans" of lines.
1233 This function populates m_line_spans with an ordered, disjoint list of
1234 the line spans of interest.
1236 Printing a gap between line spans takes one line, so, when printing
1237 line numbers, we allow a gap of up to one line between spans when
1238 merging, since it makes more sense to print the source line rather than a
1239 "gap-in-line-numbering" line. When not printing line numbers, it's
1240 better to be more explicit about what's going on, so keeping them as
1241 separate spans is preferred.
1243 For example, if the primary range is on lines 8-10, with secondary ranges
1244 covering lines 5-6 and lines 13-15:
1260 With line numbering on, we want two spans: lines 5-10 and lines 13-15.
1262 With line numbering off (with span headers), we want three spans: lines 5-6,
1263 lines 8-10, and lines 13-15. */
1266 layout::calculate_line_spans ()
1268 /* This should only be called once, by the ctor. */
1269 gcc_assert (m_line_spans
.length () == 0);
1271 /* Populate tmp_spans with individual spans, for each of
1272 m_exploc, and for m_layout_ranges. */
1273 auto_vec
<line_span
> tmp_spans (1 + m_layout_ranges
.length ());
1274 tmp_spans
.safe_push (line_span (m_exploc
.line
, m_exploc
.line
));
1275 for (unsigned int i
= 0; i
< m_layout_ranges
.length (); i
++)
1277 const layout_range
*lr
= &m_layout_ranges
[i
];
1278 gcc_assert (lr
->m_start
.m_line
<= lr
->m_finish
.m_line
);
1279 tmp_spans
.safe_push (line_span (lr
->m_start
.m_line
,
1280 lr
->m_finish
.m_line
));
1283 /* Also add spans for any fix-it hints, in case they cover other lines. */
1284 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1286 const fixit_hint
*hint
= m_fixit_hints
[i
];
1288 tmp_spans
.safe_push (get_line_span_for_fixit_hint (hint
));
1292 tmp_spans
.qsort(line_span::comparator
);
1294 /* Now iterate through tmp_spans, copying into m_line_spans, and
1295 combining where possible. */
1296 gcc_assert (tmp_spans
.length () > 0);
1297 m_line_spans
.safe_push (tmp_spans
[0]);
1298 for (unsigned int i
= 1; i
< tmp_spans
.length (); i
++)
1300 line_span
*current
= &m_line_spans
[m_line_spans
.length () - 1];
1301 const line_span
*next
= &tmp_spans
[i
];
1302 gcc_assert (next
->m_first_line
>= current
->m_first_line
);
1303 const int merger_distance
= m_show_line_numbers_p
? 1 : 0;
1304 if ((linenum_arith_t
)next
->m_first_line
1305 <= (linenum_arith_t
)current
->m_last_line
+ 1 + merger_distance
)
1307 /* We can merge them. */
1308 if (next
->m_last_line
> current
->m_last_line
)
1309 current
->m_last_line
= next
->m_last_line
;
1313 /* No merger possible. */
1314 m_line_spans
.safe_push (*next
);
1318 /* Verify the result, in m_line_spans. */
1319 gcc_assert (m_line_spans
.length () > 0);
1320 for (unsigned int i
= 1; i
< m_line_spans
.length (); i
++)
1322 const line_span
*prev
= &m_line_spans
[i
- 1];
1323 const line_span
*next
= &m_line_spans
[i
];
1324 /* The individual spans must be sane. */
1325 gcc_assert (prev
->m_first_line
<= prev
->m_last_line
);
1326 gcc_assert (next
->m_first_line
<= next
->m_last_line
);
1327 /* The spans must be ordered. */
1328 gcc_assert (prev
->m_first_line
< next
->m_first_line
);
1329 /* There must be a gap of at least one line between separate spans. */
1330 gcc_assert ((prev
->m_last_line
+ 1) < next
->m_first_line
);
1334 /* Determine how many display columns need to be reserved for line numbers,
1335 based on the largest line number that will be needed, and populate
1339 layout::calculate_linenum_width ()
1341 gcc_assert (m_line_spans
.length () > 0);
1342 const line_span
*last_span
= &m_line_spans
[m_line_spans
.length () - 1];
1343 int highest_line
= last_span
->m_last_line
;
1344 if (highest_line
< 0)
1346 m_linenum_width
= num_digits (highest_line
);
1347 /* If we're showing jumps in the line-numbering, allow at least 3 chars. */
1348 if (m_line_spans
.length () > 1)
1349 m_linenum_width
= MAX (m_linenum_width
, 3);
1350 /* If there's a minimum margin width, apply it (subtracting 1 for the space
1351 after the line number. */
1352 m_linenum_width
= MAX (m_linenum_width
, m_context
->min_margin_width
- 1);
1355 /* Calculate m_x_offset_display, which improves readability in case the source
1356 line of interest is longer than the user's display. All lines output will be
1357 shifted to the left (so that their beginning is no longer displayed) by
1358 m_x_offset_display display columns, so that the caret is in a reasonable
1362 layout::calculate_x_offset_display ()
1364 m_x_offset_display
= 0;
1366 const int max_width
= m_context
->caret_max_width
;
1369 /* Nothing to do, the width is not capped. */
1373 const char_span line
= location_get_source_line (m_exploc
.file
,
1377 /* Nothing to do, we couldn't find the source line. */
1380 int caret_display_column
= m_exploc
.m_display_col
;
1381 const int line_bytes
1382 = get_line_bytes_without_trailing_whitespace (line
.get_buffer (),
1384 int eol_display_column
1385 = cpp_display_width (line
.get_buffer (), line_bytes
);
1386 if (caret_display_column
> eol_display_column
1387 || !caret_display_column
)
1389 /* This does not make sense, so don't try to do anything in this case. */
1393 /* Adjust caret and eol positions to include the left margin. If we are
1394 outputting line numbers, then the left margin is equal to m_linenum_width
1395 plus three for the " | " which follows it. Otherwise the left margin width
1396 is equal to 1, because layout::print_source_line() will prefix each line
1398 const int source_display_cols
= eol_display_column
;
1399 int left_margin_size
= 1;
1400 if (m_show_line_numbers_p
)
1401 left_margin_size
= m_linenum_width
+ 3;
1402 caret_display_column
+= left_margin_size
;
1403 eol_display_column
+= left_margin_size
;
1405 if (eol_display_column
<= max_width
)
1407 /* Nothing to do, everything fits in the display. */
1411 /* The line is too long for the display. Calculate an offset such that the
1412 caret is not too close to the right edge of the screen. It will be
1413 CARET_LINE_MARGIN display columns from the right edge, unless it is closer
1414 than that to the end of the source line anyway. */
1415 int right_margin_size
= CARET_LINE_MARGIN
;
1416 right_margin_size
= MIN (eol_display_column
- caret_display_column
,
1418 if (right_margin_size
+ left_margin_size
>= max_width
)
1420 /* The max_width is very small, so anything we try to do will not be very
1421 effective; just punt in this case and output with no offset. */
1424 const int max_caret_display_column
= max_width
- right_margin_size
;
1425 if (caret_display_column
> max_caret_display_column
)
1427 m_x_offset_display
= caret_display_column
- max_caret_display_column
;
1428 /* Make sure we don't offset the line into oblivion. */
1429 static const int min_cols_visible
= 2;
1430 if (source_display_cols
- m_x_offset_display
< min_cols_visible
)
1431 m_x_offset_display
= 0;
1435 /* Print line ROW of source code, potentially colorized at any ranges, and
1436 populate *LBOUNDS_OUT.
1437 LINE is the source line (not necessarily 0-terminated) and LINE_BYTES
1438 is its length in bytes.
1439 This function deals only with byte offsets, not display columns, so
1440 m_x_offset_display must be converted from display to byte units. In
1441 particular, LINE_BYTES and LBOUNDS_OUT are in bytes. */
1444 layout::print_source_line (linenum_type row
, const char *line
, int line_bytes
,
1445 line_bounds
*lbounds_out
)
1447 m_colorizer
.set_normal_text ();
1449 pp_emit_prefix (m_pp
);
1450 if (m_show_line_numbers_p
)
1452 int width
= num_digits (row
);
1453 for (int i
= 0; i
< m_linenum_width
- width
; i
++)
1455 pp_printf (m_pp
, "%i | ", row
);
1460 /* We will stop printing the source line at any trailing whitespace, and start
1461 printing it as per m_x_offset_display. */
1462 line_bytes
= get_line_bytes_without_trailing_whitespace (line
,
1464 int x_offset_bytes
= 0;
1465 if (m_x_offset_display
)
1467 x_offset_bytes
= cpp_display_column_to_byte_column (line
, line_bytes
,
1468 m_x_offset_display
);
1469 /* In case the leading portion of the line that will be skipped over ends
1470 with a character with wcwidth > 1, then it is possible we skipped too
1471 much, so account for that by padding with spaces. */
1473 = cpp_byte_column_to_display_column (line
, line_bytes
, x_offset_bytes
)
1474 - m_x_offset_display
;
1475 for (int column
= 0; column
< overage
; ++column
)
1477 line
+= x_offset_bytes
;
1480 /* Print the line. */
1481 int first_non_ws
= INT_MAX
;
1482 int last_non_ws
= 0;
1483 for (int col_byte
= 1 + x_offset_bytes
; col_byte
<= line_bytes
; col_byte
++)
1485 /* Assuming colorization is enabled for the caret and underline
1486 characters, we may also colorize the associated characters
1487 within the source line.
1489 For frontends that generate range information, we color the
1490 associated characters in the source line the same as the
1491 carets and underlines in the annotation line, to make it easier
1492 for the reader to see the pertinent code.
1494 For frontends that only generate carets, we don't colorize the
1495 characters above them, since this would look strange (e.g.
1496 colorizing just the first character in a token). */
1497 if (m_colorize_source_p
)
1501 in_range_p
= get_state_at_point (row
, col_byte
,
1506 m_colorizer
.set_range (state
.range_idx
);
1508 m_colorizer
.set_normal_text ();
1511 if (c
== '\0' || c
== '\t' || c
== '\r')
1515 last_non_ws
= col_byte
;
1516 if (first_non_ws
== INT_MAX
)
1517 first_non_ws
= col_byte
;
1519 pp_character (m_pp
, c
);
1524 lbounds_out
->m_first_non_ws
= first_non_ws
;
1525 lbounds_out
->m_last_non_ws
= last_non_ws
;
1528 /* Determine if we should print an annotation line for ROW.
1529 i.e. if any of m_layout_ranges contains ROW. */
1532 layout::should_print_annotation_line_p (linenum_type row
) const
1534 layout_range
*range
;
1536 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1538 if (range
->m_range_display_kind
== SHOW_LINES_WITHOUT_RANGE
)
1540 if (range
->intersects_line_p (row
))
1546 /* Begin an annotation line. If m_show_line_numbers_p, print the left
1547 margin, which is empty for annotation lines. Otherwise, do nothing. */
1550 layout::start_annotation_line (char margin_char
) const
1552 pp_emit_prefix (m_pp
);
1553 if (m_show_line_numbers_p
)
1555 /* Print the margin. If MARGIN_CHAR != ' ', then print up to 3
1556 of it, right-aligned, padded with spaces. */
1558 for (i
= 0; i
< m_linenum_width
- 3; i
++)
1560 for (; i
< m_linenum_width
; i
++)
1561 pp_character (m_pp
, margin_char
);
1562 pp_string (m_pp
, " |");
1566 /* Print a line consisting of the caret/underlines for the given
1567 source line. This function works with display columns, rather than byte
1568 counts; in particular, LBOUNDS should be in display column units. */
1571 layout::print_annotation_line (linenum_type row
, const line_bounds lbounds
)
1573 int x_bound
= get_x_bound_for_row (row
, m_exploc
.m_display_col
,
1574 lbounds
.m_last_non_ws
);
1576 start_annotation_line ();
1579 for (int column
= 1 + m_x_offset_display
; column
< x_bound
; column
++)
1583 in_range_p
= get_state_at_point (row
, column
,
1584 lbounds
.m_first_non_ws
,
1585 lbounds
.m_last_non_ws
,
1590 /* Within a range. Draw either the caret or an underline. */
1591 m_colorizer
.set_range (state
.range_idx
);
1592 if (state
.draw_caret_p
)
1594 /* Draw the caret. */
1596 if (state
.range_idx
< rich_location::STATICALLY_ALLOCATED_RANGES
)
1597 caret_char
= m_context
->caret_chars
[state
.range_idx
];
1600 pp_character (m_pp
, caret_char
);
1603 pp_character (m_pp
, '~');
1607 /* Not in a range. */
1608 m_colorizer
.set_normal_text ();
1609 pp_character (m_pp
, ' ');
1615 /* Implementation detail of layout::print_any_labels.
1617 A label within the given row of source. */
1622 line_label (int state_idx
, int column
, label_text text
)
1623 : m_state_idx (state_idx
), m_column (column
),
1624 m_text (text
), m_label_line (0), m_has_vbar (true)
1626 const int bytes
= strlen (text
.m_buffer
);
1627 m_display_width
= cpp_display_width (text
.m_buffer
, bytes
);
1630 /* Sorting is primarily by column, then by state index. */
1631 static int comparator (const void *p1
, const void *p2
)
1633 const line_label
*ll1
= (const line_label
*)p1
;
1634 const line_label
*ll2
= (const line_label
*)p2
;
1635 int column_cmp
= compare (ll1
->m_column
, ll2
->m_column
);
1638 /* Order by reverse state index, so that labels are printed
1639 in order of insertion into the rich_location when the
1640 sorted list is walked backwards. */
1641 return -compare (ll1
->m_state_idx
, ll2
->m_state_idx
);
1647 size_t m_display_width
;
1652 /* Print any labels in this row. */
1654 layout::print_any_labels (linenum_type row
)
1657 auto_vec
<line_label
> labels
;
1659 /* Gather the labels that are to be printed into "labels". */
1661 layout_range
*range
;
1662 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1664 /* Most ranges don't have labels, so reject this first. */
1665 if (range
->m_label
== NULL
)
1668 /* The range's caret must be on this line. */
1669 if (range
->m_caret
.m_line
!= row
)
1672 /* Reject labels that aren't fully visible due to clipping
1673 by m_x_offset_display. */
1674 const int disp_col
= range
->m_caret
.m_columns
[CU_DISPLAY_COLS
];
1675 if (disp_col
<= m_x_offset_display
)
1679 text
= range
->m_label
->get_text (range
->m_original_idx
);
1681 /* Allow for labels that return NULL from their get_text
1682 implementation (so e.g. such labels can control their own
1684 if (text
.m_buffer
== NULL
)
1687 labels
.safe_push (line_label (i
, disp_col
, text
));
1691 /* Bail out if there are no labels on this row. */
1692 if (labels
.length () == 0)
1696 labels
.qsort(line_label::comparator
);
1698 /* Figure out how many "label lines" we need, and which
1699 one each label is printed in.
1701 For example, if the labels aren't too densely packed,
1702 we can fit them on the same line, giving two "label lines":
1707 l0 l1 : label line 1
1709 If they would touch each other or overlap, then we need
1710 additional "label lines":
1715 | label 1 : label line 1
1716 label 0 : label line 2
1718 Place the final label on label line 1, and work backwards, adding
1719 label lines as needed.
1721 If multiple labels are at the same place, put them on separate
1727 label 0 : label line 2
1728 label 1 : label line 3. */
1730 int max_label_line
= 1;
1732 int next_column
= INT_MAX
;
1734 FOR_EACH_VEC_ELT_REVERSE (labels
, i
, label
)
1736 /* Would this label "touch" or overlap the next label? */
1737 if (label
->m_column
+ label
->m_display_width
>= (size_t)next_column
)
1741 /* If we've already seen labels with the same column, suppress the
1742 vertical bar for subsequent ones in this backwards iteration;
1743 hence only the one with the highest label_line has m_has_vbar set. */
1744 if (label
->m_column
== next_column
)
1745 label
->m_has_vbar
= false;
1748 label
->m_label_line
= max_label_line
;
1749 next_column
= label
->m_column
;
1753 /* Print the "label lines". For each label within the line, print
1754 either a vertical bar ('|') for the labels that are lower down, or the
1755 labels themselves once we've reached their line. */
1757 for (int label_line
= 0; label_line
<= max_label_line
; label_line
++)
1759 start_annotation_line ();
1761 int column
= 1 + m_x_offset_display
;
1763 FOR_EACH_VEC_ELT (labels
, i
, label
)
1765 if (label_line
> label
->m_label_line
)
1766 /* We've printed all the labels for this label line. */
1769 if (label_line
== label
->m_label_line
)
1771 gcc_assert (column
<= label
->m_column
);
1772 move_to_column (&column
, label
->m_column
, true);
1773 m_colorizer
.set_range (label
->m_state_idx
);
1774 pp_string (m_pp
, label
->m_text
.m_buffer
);
1775 m_colorizer
.set_normal_text ();
1776 column
+= label
->m_display_width
;
1778 else if (label
->m_has_vbar
)
1780 gcc_assert (column
<= label
->m_column
);
1781 move_to_column (&column
, label
->m_column
, true);
1782 m_colorizer
.set_range (label
->m_state_idx
);
1783 pp_character (m_pp
, '|');
1784 m_colorizer
.set_normal_text ();
1795 FOR_EACH_VEC_ELT (labels
, i
, label
)
1796 label
->m_text
.maybe_free ();
1800 /* If there are any fixit hints inserting new lines before source line ROW,
1803 They are printed on lines of their own, before the source line
1804 itself, with a leading '+'. */
1807 layout::print_leading_fixits (linenum_type row
)
1809 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
1811 const fixit_hint
*hint
= m_fixit_hints
[i
];
1813 if (!hint
->ends_with_newline_p ())
1814 /* Not a newline fixit; print it in print_trailing_fixits. */
1817 gcc_assert (hint
->insertion_p ());
1819 if (hint
->affects_line_p (m_exploc
.file
, row
))
1821 /* Printing the '+' with normal colorization
1822 and the inserted line with "insert" colorization
1823 helps them stand out from each other, and from
1824 the surrounding text. */
1825 m_colorizer
.set_normal_text ();
1826 start_annotation_line ('+');
1827 pp_character (m_pp
, '+');
1828 m_colorizer
.set_fixit_insert ();
1829 /* Print all but the trailing newline of the fix-it hint.
1830 We have to print the newline separately to avoid
1831 getting additional pp prefixes printed. */
1832 for (size_t i
= 0; i
< hint
->get_length () - 1; i
++)
1833 pp_character (m_pp
, hint
->get_string ()[i
]);
1834 m_colorizer
.set_normal_text ();
1840 /* Subroutine of layout::print_trailing_fixits.
1842 Determine if the annotation line printed for LINE contained
1843 the exact range from START_COLUMN to FINISH_COLUMN (in display units). */
1846 layout::annotation_line_showed_range_p (linenum_type line
, int start_column
,
1847 int finish_column
) const
1849 layout_range
*range
;
1851 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
1852 if (range
->m_start
.m_line
== line
1853 && range
->m_start
.m_columns
[CU_DISPLAY_COLS
] == start_column
1854 && range
->m_finish
.m_line
== line
1855 && range
->m_finish
.m_columns
[CU_DISPLAY_COLS
] == finish_column
)
1860 /* Classes for printing trailing fix-it hints i.e. those that
1861 don't add new lines.
1863 For insertion, these can look like:
1867 For replacement, these can look like:
1869 ------------- : underline showing affected range
1872 For deletion, these can look like:
1874 ------------- : underline showing affected range
1876 This can become confusing if they overlap, and so we need
1877 to do some preprocessing to decide what to print.
1878 We use the list of fixit_hint instances affecting the line
1879 to build a list of "correction" instances, and print the
1882 For example, consider a set of fix-its for converting
1883 a C-style cast to a C++ const_cast.
1887 ..000000000111111111122222222223333333333.
1888 ..123456789012345678901234567890123456789.
1889 foo *f = (foo *)ptr->field;
1892 and the fix-it hints:
1893 - replace col 10 (the open paren) with "const_cast<"
1894 - replace col 16 (the close paren) with "> ("
1895 - insert ")" before col 27
1897 then we would get odd-looking output:
1899 foo *f = (foo *)ptr->field;
1906 It would be better to detect when fixit hints are going to
1907 overlap (those that require new lines), and to consolidate
1908 the printing of such fixits, giving something like:
1910 foo *f = (foo *)ptr->field;
1913 const_cast<foo *> (ptr->field)
1915 This works by detecting when the printing would overlap, and
1916 effectively injecting no-op replace hints into the gaps between
1917 such fix-its, so that the printing joins up.
1919 In the above example, the overlap of:
1920 - replace col 10 (the open paren) with "const_cast<"
1922 - replace col 16 (the close paren) with "> ("
1923 is fixed by injecting a no-op:
1924 - replace cols 11-15 with themselves ("foo *")
1925 and consolidating these, making:
1926 - replace cols 10-16 with "const_cast<" + "foo *" + "> ("
1928 - replace cols 10-16 with "const_cast<foo *> ("
1930 This overlaps with the final fix-it hint:
1931 - insert ")" before col 27
1932 and so we repeat the consolidation process, by injecting
1934 - replace cols 17-26 with themselves ("ptr->field")
1936 - replace cols 10-26 with "const_cast<foo *> (" + "ptr->field" + ")"
1938 - replace cols 10-26 with "const_cast<foo *> (ptr->field)"
1940 and is thus printed as desired. */
1942 /* A range of (byte or display) columns within a line. */
1947 column_range (int start_
, int finish_
) : start (start_
), finish (finish_
)
1949 /* We must have either a range, or an insertion. */
1950 gcc_assert (start
<= finish
|| finish
== start
- 1);
1953 bool operator== (const column_range
&other
) const
1955 return start
== other
.start
&& finish
== other
.finish
;
1962 /* Get the range of bytes or display columns that HINT would affect. */
1964 get_affected_range (const fixit_hint
*hint
, enum column_unit col_unit
)
1966 expanded_location exploc_start
= expand_location (hint
->get_start_loc ());
1967 expanded_location exploc_finish
= expand_location (hint
->get_next_loc ());
1968 --exploc_finish
.column
;
1972 if (col_unit
== CU_DISPLAY_COLS
)
1974 start_column
= location_compute_display_column (exploc_start
);
1975 if (hint
->insertion_p ())
1976 finish_column
= start_column
- 1;
1978 finish_column
= location_compute_display_column (exploc_finish
);
1982 start_column
= exploc_start
.column
;
1983 finish_column
= exploc_finish
.column
;
1985 return column_range (start_column
, finish_column
);
1988 /* Get the range of display columns that would be printed for HINT. */
1991 get_printed_columns (const fixit_hint
*hint
)
1993 expanded_location exploc
= expand_location (hint
->get_start_loc ());
1994 int start_column
= location_compute_display_column (exploc
);
1995 int hint_width
= cpp_display_width (hint
->get_string (),
1996 hint
->get_length ());
1997 int final_hint_column
= start_column
+ hint_width
- 1;
1998 if (hint
->insertion_p ())
2000 return column_range (start_column
, final_hint_column
);
2004 exploc
= expand_location (hint
->get_next_loc ());
2006 int finish_column
= location_compute_display_column (exploc
);
2007 return column_range (start_column
,
2008 MAX (finish_column
, final_hint_column
));
2012 /* A correction on a particular line.
2013 This describes a plan for how to print one or more fixit_hint
2014 instances that affected the line, potentially consolidating hints
2015 into corrections to make the result easier for the user to read. */
2020 correction (column_range affected_bytes
,
2021 column_range affected_columns
,
2022 column_range printed_columns
,
2023 const char *new_text
, size_t new_text_len
)
2024 : m_affected_bytes (affected_bytes
),
2025 m_affected_columns (affected_columns
),
2026 m_printed_columns (printed_columns
),
2027 m_text (xstrdup (new_text
)),
2028 m_byte_length (new_text_len
),
2029 m_alloc_sz (new_text_len
+ 1)
2031 compute_display_cols ();
2034 ~correction () { free (m_text
); }
2036 bool insertion_p () const
2038 return m_affected_bytes
.start
== m_affected_bytes
.finish
+ 1;
2041 void ensure_capacity (size_t len
);
2042 void ensure_terminated ();
2044 void compute_display_cols ()
2046 m_display_cols
= cpp_display_width (m_text
, m_byte_length
);
2049 void overwrite (int dst_offset
, const char_span
&src_span
)
2051 gcc_assert (dst_offset
>= 0);
2052 gcc_assert (dst_offset
+ src_span
.length () < m_alloc_sz
);
2053 memcpy (m_text
+ dst_offset
, src_span
.get_buffer (),
2054 src_span
.length ());
2057 /* If insert, then start: the column before which the text
2058 is to be inserted, and finish is offset by the length of
2060 If replace, then the range of columns affected. */
2061 column_range m_affected_bytes
;
2062 column_range m_affected_columns
;
2064 /* If insert, then start: the column before which the text
2065 is to be inserted, and finish is offset by the length of
2067 If replace, then the range of columns affected. */
2068 column_range m_printed_columns
;
2070 /* The text to be inserted/used as replacement. */
2072 size_t m_byte_length
; /* Not including null-terminator. */
2077 /* Ensure that m_text can hold a string of length LEN
2078 (plus 1 for 0-termination). */
2081 correction::ensure_capacity (size_t len
)
2083 /* Allow 1 extra byte for 0-termination. */
2084 if (m_alloc_sz
< (len
+ 1))
2086 size_t new_alloc_sz
= (len
+ 1) * 2;
2087 m_text
= (char *)xrealloc (m_text
, new_alloc_sz
);
2088 m_alloc_sz
= new_alloc_sz
;
2092 /* Ensure that m_text is 0-terminated. */
2095 correction::ensure_terminated ()
2097 /* 0-terminate the buffer. */
2098 gcc_assert (m_byte_length
< m_alloc_sz
);
2099 m_text
[m_byte_length
] = '\0';
2102 /* A list of corrections affecting a particular line.
2103 This is used by layout::print_trailing_fixits for planning
2104 how to print the fix-it hints affecting the line. */
2106 class line_corrections
2109 line_corrections (const char *filename
, linenum_type row
)
2110 : m_filename (filename
), m_row (row
)
2112 ~line_corrections ();
2114 void add_hint (const fixit_hint
*hint
);
2116 const char *m_filename
;
2118 auto_vec
<correction
*> m_corrections
;
2121 /* struct line_corrections. */
2123 line_corrections::~line_corrections ()
2127 FOR_EACH_VEC_ELT (m_corrections
, i
, c
)
2131 /* A struct wrapping a particular source line, allowing
2132 run-time bounds-checking of accesses in a checked build. */
2137 source_line (const char *filename
, int line
);
2139 char_span
as_span () { return char_span (chars
, width
); }
2145 /* source_line's ctor. */
2147 source_line::source_line (const char *filename
, int line
)
2149 char_span span
= location_get_source_line (filename
, line
);
2150 chars
= span
.get_buffer ();
2151 width
= span
.length ();
2154 /* Add HINT to the corrections for this line.
2155 Attempt to consolidate nearby hints so that they will not
2156 overlap with printed. */
2159 line_corrections::add_hint (const fixit_hint
*hint
)
2161 column_range affected_bytes
= get_affected_range (hint
, CU_BYTES
);
2162 column_range affected_columns
= get_affected_range (hint
, CU_DISPLAY_COLS
);
2163 column_range printed_columns
= get_printed_columns (hint
);
2165 /* Potentially consolidate. */
2166 if (!m_corrections
.is_empty ())
2168 correction
*last_correction
2169 = m_corrections
[m_corrections
.length () - 1];
2171 /* The following consolidation code assumes that the fix-it hints
2172 have been sorted by start (done within layout's ctor). */
2173 gcc_assert (affected_bytes
.start
2174 >= last_correction
->m_affected_bytes
.start
);
2175 gcc_assert (printed_columns
.start
2176 >= last_correction
->m_printed_columns
.start
);
2178 if (printed_columns
.start
<= last_correction
->m_printed_columns
.finish
)
2180 /* We have two hints for which the printed forms of the hints
2181 would touch or overlap, so we need to consolidate them to avoid
2183 Attempt to inject a "replace" correction from immediately
2184 after the end of the last hint to immediately before the start
2185 of the next hint. */
2186 column_range
between (last_correction
->m_affected_bytes
.finish
+ 1,
2187 affected_bytes
.start
- 1);
2189 /* Try to read the source. */
2190 source_line
line (m_filename
, m_row
);
2191 if (line
.chars
&& between
.finish
< line
.width
)
2193 /* Consolidate into the last correction:
2194 add a no-op "replace" of the "between" text, and
2195 add the text from the new hint. */
2196 int old_byte_len
= last_correction
->m_byte_length
;
2197 gcc_assert (old_byte_len
>= 0);
2198 int between_byte_len
= between
.finish
+ 1 - between
.start
;
2199 gcc_assert (between_byte_len
>= 0);
2201 = old_byte_len
+ between_byte_len
+ hint
->get_length ();
2202 gcc_assert (new_byte_len
>= 0);
2203 last_correction
->ensure_capacity (new_byte_len
);
2204 last_correction
->overwrite
2206 line
.as_span ().subspan (between
.start
- 1,
2207 between
.finish
+ 1 - between
.start
));
2208 last_correction
->overwrite (old_byte_len
+ between_byte_len
,
2209 char_span (hint
->get_string (),
2210 hint
->get_length ()));
2211 last_correction
->m_byte_length
= new_byte_len
;
2212 last_correction
->ensure_terminated ();
2213 last_correction
->m_affected_bytes
.finish
2214 = affected_bytes
.finish
;
2215 last_correction
->m_affected_columns
.finish
2216 = affected_columns
.finish
;
2217 int prev_display_cols
= last_correction
->m_display_cols
;
2218 last_correction
->compute_display_cols ();
2219 last_correction
->m_printed_columns
.finish
2220 += last_correction
->m_display_cols
- prev_display_cols
;
2226 /* If no consolidation happened, add a new correction instance. */
2227 m_corrections
.safe_push (new correction (affected_bytes
,
2230 hint
->get_string (),
2231 hint
->get_length ()));
2234 /* If there are any fixit hints on source line ROW, print them.
2235 They are printed in order, attempting to combine them onto lines, but
2236 starting new lines if necessary.
2237 Fix-it hints that insert new lines are handled separately,
2238 in layout::print_leading_fixits. */
2241 layout::print_trailing_fixits (linenum_type row
)
2243 /* Build a list of correction instances for the line,
2244 potentially consolidating hints (for the sake of readability). */
2245 line_corrections
corrections (m_exploc
.file
, row
);
2246 for (unsigned int i
= 0; i
< m_fixit_hints
.length (); i
++)
2248 const fixit_hint
*hint
= m_fixit_hints
[i
];
2250 /* Newline fixits are handled by layout::print_leading_fixits. */
2251 if (hint
->ends_with_newline_p ())
2254 if (hint
->affects_line_p (m_exploc
.file
, row
))
2255 corrections
.add_hint (hint
);
2258 /* Now print the corrections. */
2261 int column
= m_x_offset_display
;
2263 if (!corrections
.m_corrections
.is_empty ())
2264 start_annotation_line ();
2266 FOR_EACH_VEC_ELT (corrections
.m_corrections
, i
, c
)
2268 /* For now we assume each fixit hint can only touch one line. */
2269 if (c
->insertion_p ())
2271 /* This assumes the insertion just affects one line. */
2272 int start_column
= c
->m_printed_columns
.start
;
2273 move_to_column (&column
, start_column
, true);
2274 m_colorizer
.set_fixit_insert ();
2275 pp_string (m_pp
, c
->m_text
);
2276 m_colorizer
.set_normal_text ();
2277 column
+= c
->m_display_cols
;
2281 /* If the range of the replacement wasn't printed in the
2282 annotation line, then print an extra underline to
2283 indicate exactly what is being replaced.
2284 Always show it for removals. */
2285 int start_column
= c
->m_affected_columns
.start
;
2286 int finish_column
= c
->m_affected_columns
.finish
;
2287 if (!annotation_line_showed_range_p (row
, start_column
,
2289 || c
->m_byte_length
== 0)
2291 move_to_column (&column
, start_column
, true);
2292 m_colorizer
.set_fixit_delete ();
2293 for (; column
<= finish_column
; column
++)
2294 pp_character (m_pp
, '-');
2295 m_colorizer
.set_normal_text ();
2297 /* Print the replacement text. REPLACE also covers
2298 removals, so only do this extra work (potentially starting
2299 a new line) if we have actual replacement text. */
2300 if (c
->m_byte_length
> 0)
2302 move_to_column (&column
, start_column
, true);
2303 m_colorizer
.set_fixit_insert ();
2304 pp_string (m_pp
, c
->m_text
);
2305 m_colorizer
.set_normal_text ();
2306 column
+= c
->m_display_cols
;
2311 /* Add a trailing newline, if necessary. */
2312 move_to_column (&column
, 0, false);
2315 /* Disable any colorization and emit a newline. */
2318 layout::print_newline ()
2320 m_colorizer
.set_normal_text ();
2324 /* Return true if (ROW/COLUMN) is within a range of the layout.
2325 If it returns true, OUT_STATE is written to, with the
2326 range index, and whether we should draw the caret at
2327 (ROW/COLUMN) (as opposed to an underline). COL_UNIT controls
2328 whether all inputs and outputs are in bytes or display column units. */
2331 layout::get_state_at_point (/* Inputs. */
2332 linenum_type row
, int column
,
2333 int first_non_ws
, int last_non_ws
,
2334 enum column_unit col_unit
,
2336 point_state
*out_state
)
2338 layout_range
*range
;
2340 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
2342 if (range
->m_range_display_kind
== SHOW_LINES_WITHOUT_RANGE
)
2343 /* Bail out early, so that such ranges don't affect underlining or
2344 source colorization. */
2347 if (range
->contains_point (row
, column
, col_unit
))
2349 out_state
->range_idx
= i
;
2351 /* Are we at the range's caret? is it visible? */
2352 out_state
->draw_caret_p
= false;
2353 if (range
->m_range_display_kind
== SHOW_RANGE_WITH_CARET
2354 && row
== range
->m_caret
.m_line
2355 && column
== range
->m_caret
.m_columns
[col_unit
])
2356 out_state
->draw_caret_p
= true;
2358 /* Within a multiline range, don't display any underline
2359 in any leading or trailing whitespace on a line.
2360 We do display carets, however. */
2361 if (!out_state
->draw_caret_p
)
2362 if (column
< first_non_ws
|| column
> last_non_ws
)
2365 /* We are within a range. */
2373 /* Helper function for use by layout::print_line when printing the
2374 annotation line under the source line.
2375 Get the display column beyond the rightmost one that could contain a caret
2376 or range marker, given that we stop rendering at trailing whitespace.
2377 ROW is the source line within the given file.
2378 CARET_COLUMN is the display column of range 0's caret.
2379 LAST_NON_WS_COLUMN is the last display column containing a non-whitespace
2380 character of source (as determined when printing the source line). */
2383 layout::get_x_bound_for_row (linenum_type row
, int caret_column
,
2384 int last_non_ws_column
)
2386 int result
= caret_column
+ 1;
2388 layout_range
*range
;
2390 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
2392 if (row
>= range
->m_start
.m_line
)
2394 if (range
->m_finish
.m_line
== row
)
2396 /* On the final line within a range; ensure that
2397 we render up to the end of the range. */
2398 const int disp_col
= range
->m_finish
.m_columns
[CU_DISPLAY_COLS
];
2399 if (result
<= disp_col
)
2400 result
= disp_col
+ 1;
2402 else if (row
< range
->m_finish
.m_line
)
2404 /* Within a multiline range; ensure that we render up to the
2405 last non-whitespace column. */
2406 if (result
<= last_non_ws_column
)
2407 result
= last_non_ws_column
+ 1;
2415 /* Given *COLUMN as an x-coordinate, print spaces to position
2416 successive output at DEST_COLUMN, printing a newline if necessary,
2417 and updating *COLUMN. If ADD_LEFT_MARGIN, then print the (empty)
2418 left margin after any newline. */
2421 layout::move_to_column (int *column
, int dest_column
, bool add_left_margin
)
2423 /* Start a new line if we need to. */
2424 if (*column
> dest_column
)
2427 if (add_left_margin
)
2428 start_annotation_line ();
2429 *column
= m_x_offset_display
;
2432 while (*column
< dest_column
)
2439 /* For debugging layout issues, render a ruler giving column numbers
2440 (after the 1-column indent). */
2443 layout::show_ruler (int max_column
) const
2446 if (max_column
> 99)
2448 start_annotation_line ();
2450 for (int column
= 1 + m_x_offset_display
; column
<= max_column
; column
++)
2451 if (column
% 10 == 0)
2452 pp_character (m_pp
, '0' + (column
/ 100) % 10);
2459 start_annotation_line ();
2461 for (int column
= 1 + m_x_offset_display
; column
<= max_column
; column
++)
2462 if (column
% 10 == 0)
2463 pp_character (m_pp
, '0' + (column
/ 10) % 10);
2469 start_annotation_line ();
2471 for (int column
= 1 + m_x_offset_display
; column
<= max_column
; column
++)
2472 pp_character (m_pp
, '0' + (column
% 10));
2476 /* Print leading fix-its (for new lines inserted before the source line)
2477 then the source line, followed by an annotation line
2478 consisting of any caret/underlines, then any fixits.
2479 If the source line can't be read, print nothing. */
2481 layout::print_line (linenum_type row
)
2483 char_span line
= location_get_source_line (m_exploc
.file
, row
);
2487 line_bounds lbounds
;
2488 print_leading_fixits (row
);
2489 print_source_line (row
, line
.get_buffer (), line
.length (), &lbounds
);
2490 if (should_print_annotation_line_p (row
))
2492 if (lbounds
.m_first_non_ws
!= INT_MAX
)
2493 lbounds
.convert_to_display_cols (line
);
2494 print_annotation_line (row
, lbounds
);
2496 if (m_show_labels_p
)
2497 print_any_labels (row
);
2498 print_trailing_fixits (row
);
2501 } /* End of anonymous namespace. */
2503 /* If LOC is within the spans of lines that will already be printed for
2504 this gcc_rich_location, then add it as a secondary location and return true.
2506 Otherwise return false. */
2509 gcc_rich_location::add_location_if_nearby (location_t loc
)
2511 /* Use the layout location-handling logic to sanitize LOC,
2512 filtering it to the current line spans within a temporary
2514 layout
layout (global_dc
, this, DK_ERROR
);
2515 location_range loc_range
;
2516 loc_range
.m_loc
= loc
;
2517 loc_range
.m_range_display_kind
= SHOW_RANGE_WITHOUT_CARET
;
2518 if (!layout
.maybe_add_location_range (&loc_range
, 0, true))
2525 /* Print the physical source code corresponding to the location of
2526 this diagnostic, with additional annotations. */
2529 diagnostic_show_locus (diagnostic_context
* context
,
2530 rich_location
*richloc
,
2531 diagnostic_t diagnostic_kind
)
2533 pp_newline (context
->printer
);
2535 location_t loc
= richloc
->get_loc ();
2536 /* Do nothing if source-printing has been disabled. */
2537 if (!context
->show_caret
)
2540 /* Don't attempt to print source for UNKNOWN_LOCATION and for builtins. */
2541 if (loc
<= BUILTINS_LOCATION
)
2544 /* Don't print the same source location twice in a row, unless we have
2546 if (loc
== context
->last_location
2547 && richloc
->get_num_fixit_hints () == 0)
2550 context
->last_location
= loc
;
2552 layout
layout (context
, richloc
, diagnostic_kind
);
2553 for (int line_span_idx
= 0; line_span_idx
< layout
.get_num_line_spans ();
2556 const line_span
*line_span
= layout
.get_line_span (line_span_idx
);
2557 if (context
->show_line_numbers_p
)
2559 /* With line numbers, we should show whenever the line-numbering
2561 if (line_span_idx
> 0)
2562 layout
.print_gap_in_line_numbering ();
2566 /* Without line numbers, we print headings for some line spans. */
2567 if (layout
.print_heading_for_line_span_index_p (line_span_idx
))
2569 expanded_location exploc
2570 = layout
.get_expanded_location (line_span
);
2571 context
->start_span (context
, exploc
);
2574 /* Iterate over the lines within this span (using linenum_arith_t to
2575 avoid overflow with 0xffffffff causing an infinite loop). */
2576 linenum_arith_t last_line
= line_span
->get_last_line ();
2577 for (linenum_arith_t row
= line_span
->get_first_line ();
2578 row
<= last_line
; row
++)
2579 layout
.print_line (row
);
2585 namespace selftest
{
2587 /* Selftests for diagnostic_show_locus. */
2589 /* For precise tests of the layout, make clear where the source line will
2590 start. test_left_margin sets the total byte count from the left side of the
2591 screen to the start of source lines, after the line number and the separator,
2592 which consists of the three characters " | ". */
2593 static const int test_linenum_sep
= 3;
2594 static const int test_left_margin
= 7;
2596 /* Helper function for test_layout_x_offset_display_utf8(). */
2598 test_offset_impl (int caret_byte_col
, int max_width
,
2599 int expected_x_offset_display
,
2600 int left_margin
= test_left_margin
)
2602 test_diagnostic_context dc
;
2603 dc
.caret_max_width
= max_width
;
2604 /* diagnostic_context::min_margin_width sets the minimum space reserved for
2605 the line number plus one space after. */
2606 dc
.min_margin_width
= left_margin
- test_linenum_sep
+ 1;
2607 dc
.show_line_numbers_p
= true;
2608 rich_location
richloc (line_table
,
2609 linemap_position_for_column (line_table
,
2611 layout
test_layout (&dc
, &richloc
, DK_ERROR
);
2612 ASSERT_EQ (left_margin
- test_linenum_sep
,
2613 test_layout
.get_linenum_width ());
2614 ASSERT_EQ (expected_x_offset_display
,
2615 test_layout
.get_x_offset_display ());
2618 /* Test that layout::calculate_x_offset_display() works. */
2620 test_layout_x_offset_display_utf8 (const line_table_case
&case_
)
2624 = "This line is very long, so that we can use it to test the logic for "
2625 "clipping long lines. Also this: \xf0\x9f\x98\x82\xf0\x9f\x98\x82 is a "
2626 "pair of emojis that occupies 8 bytes and 4 display columns, starting at "
2629 /* Number of bytes in the line, subtracting one to remove the newline. */
2630 const int line_bytes
= strlen (content
) - 1;
2632 /* Number of display columns occupied by the line; each of the 2 emojis
2633 takes up 2 fewer display columns than it does bytes. */
2634 const int line_display_cols
= line_bytes
- 2*2;
2636 /* The column of the first emoji. Byte or display is the same as there are
2637 no multibyte characters earlier on the line. */
2638 const int emoji_col
= 102;
2640 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
2641 line_table_test
ltt (case_
);
2643 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 1);
2645 location_t line_end
= linemap_position_for_column (line_table
, line_bytes
);
2647 /* Don't attempt to run the tests if column data might be unavailable. */
2648 if (line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
2651 ASSERT_STREQ (tmp
.get_filename (), LOCATION_FILE (line_end
));
2652 ASSERT_EQ (1, LOCATION_LINE (line_end
));
2653 ASSERT_EQ (line_bytes
, LOCATION_COLUMN (line_end
));
2655 char_span lspan
= location_get_source_line (tmp
.get_filename (), 1);
2656 ASSERT_EQ (line_display_cols
,
2657 cpp_display_width (lspan
.get_buffer (), lspan
.length ()));
2658 ASSERT_EQ (line_display_cols
,
2659 location_compute_display_column (expand_location (line_end
)));
2660 ASSERT_EQ (0, memcmp (lspan
.get_buffer () + (emoji_col
- 1),
2661 "\xf0\x9f\x98\x82\xf0\x9f\x98\x82", 8));
2663 /* (caret_byte, max_width, expected_x_offset_display, [left_margin]) */
2665 /* No constraint on the width -> no offset. */
2666 test_offset_impl (emoji_col
, 0, 0);
2668 /* Caret is before the beginning -> no offset. */
2669 test_offset_impl (0, 100, 0);
2671 /* Caret is past the end of the line -> no offset. */
2672 test_offset_impl (line_bytes
+1, 100, 0);
2674 /* Line fits in the display -> no offset. */
2675 test_offset_impl (line_bytes
, line_display_cols
+ test_left_margin
, 0);
2676 test_offset_impl (emoji_col
, line_display_cols
+ test_left_margin
, 0);
2678 /* Line is too long for the display but caret location is OK
2679 anyway -> no offset. */
2680 static const int small_width
= 24;
2681 test_offset_impl (1, small_width
, 0);
2683 /* Width constraint is very small -> no offset. */
2684 test_offset_impl (emoji_col
, CARET_LINE_MARGIN
, 0);
2686 /* Line would be offset, but due to large line numbers, offsetting
2687 would remove the whole line -> no offset. */
2688 static const int huge_left_margin
= 100;
2689 test_offset_impl (emoji_col
, huge_left_margin
, 0, huge_left_margin
);
2691 /* Line is the same length as the display, but the line number makes it too
2692 long, so offset is required. Caret is at the end so padding on the right
2693 is not in effect. */
2694 for (int excess
= 1; excess
<= 3; ++excess
)
2695 test_offset_impl (line_bytes
, line_display_cols
+ test_left_margin
- excess
,
2698 /* Line is much too long for the display, caret is near the end ->
2699 offset should be such that the line fits in the display and caret
2700 remains the same distance from the end that it was. */
2701 for (int caret_offset
= 0, max_offset
= MIN (CARET_LINE_MARGIN
, 10);
2702 caret_offset
<= max_offset
; ++caret_offset
)
2703 test_offset_impl (line_bytes
- caret_offset
, small_width
,
2704 line_display_cols
+ test_left_margin
- small_width
);
2706 /* As previous case but caret is closer to the middle; now we want it to end
2707 up CARET_LINE_MARGIN bytes from the end. */
2708 ASSERT_GT (line_display_cols
- emoji_col
, CARET_LINE_MARGIN
);
2709 test_offset_impl (emoji_col
, small_width
,
2710 emoji_col
+ test_left_margin
2711 - (small_width
- CARET_LINE_MARGIN
));
2713 /* Test that the source line is offset as expected when printed. */
2715 test_diagnostic_context dc
;
2716 dc
.caret_max_width
= small_width
- 6;
2717 dc
.min_margin_width
= test_left_margin
- test_linenum_sep
+ 1;
2718 dc
.show_line_numbers_p
= true;
2719 dc
.show_ruler_p
= true;
2720 rich_location
richloc (line_table
,
2721 linemap_position_for_column (line_table
,
2723 layout
test_layout (&dc
, &richloc
, DK_ERROR
);
2724 test_layout
.print_line (1);
2725 ASSERT_STREQ (" | 1 \n"
2727 " | 234567890123456789\n"
2728 " 1 | \xf0\x9f\x98\x82\xf0\x9f\x98\x82 is a pair of emojis "
2729 "that occupies 8 bytes and 4 display columns, starting at "
2732 pp_formatted_text (dc
.printer
));
2735 /* Similar to the previous example, but now the offset called for would split
2736 the first emoji in the middle of the UTF-8 sequence. Check that we replace
2737 it with a padding space in this case. */
2739 test_diagnostic_context dc
;
2740 dc
.caret_max_width
= small_width
- 5;
2741 dc
.min_margin_width
= test_left_margin
- test_linenum_sep
+ 1;
2742 dc
.show_line_numbers_p
= true;
2743 dc
.show_ruler_p
= true;
2744 rich_location
richloc (line_table
,
2745 linemap_position_for_column (line_table
,
2747 layout
test_layout (&dc
, &richloc
, DK_ERROR
);
2748 test_layout
.print_line (1);
2749 ASSERT_STREQ (" | 1 1 \n"
2751 " | 3456789012345678901\n"
2752 " 1 | \xf0\x9f\x98\x82 is a pair of emojis "
2753 "that occupies 8 bytes and 4 display columns, starting at "
2756 pp_formatted_text (dc
.printer
));
2761 /* Verify that diagnostic_show_locus works sanely on UNKNOWN_LOCATION. */
2764 test_diagnostic_show_locus_unknown_location ()
2766 test_diagnostic_context dc
;
2767 rich_location
richloc (line_table
, UNKNOWN_LOCATION
);
2768 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2769 ASSERT_STREQ ("\n", pp_formatted_text (dc
.printer
));
2772 /* Verify that diagnostic_show_locus works sanely for various
2775 All of these work on the following 1-line source file:
2778 "foo = bar.field;\n"
2779 which is set up by test_diagnostic_show_locus_one_liner and calls
2785 test_one_liner_simple_caret ()
2787 test_diagnostic_context dc
;
2788 location_t caret
= linemap_position_for_column (line_table
, 10);
2789 rich_location
richloc (line_table
, caret
);
2790 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2792 " foo = bar.field;\n"
2794 pp_formatted_text (dc
.printer
));
2797 /* Caret and range. */
2800 test_one_liner_caret_and_range ()
2802 test_diagnostic_context dc
;
2803 location_t caret
= linemap_position_for_column (line_table
, 10);
2804 location_t start
= linemap_position_for_column (line_table
, 7);
2805 location_t finish
= linemap_position_for_column (line_table
, 15);
2806 location_t loc
= make_location (caret
, start
, finish
);
2807 rich_location
richloc (line_table
, loc
);
2808 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2810 " foo = bar.field;\n"
2812 pp_formatted_text (dc
.printer
));
2815 /* Multiple ranges and carets. */
2818 test_one_liner_multiple_carets_and_ranges ()
2820 test_diagnostic_context dc
;
2822 = make_location (linemap_position_for_column (line_table
, 2),
2823 linemap_position_for_column (line_table
, 1),
2824 linemap_position_for_column (line_table
, 3));
2825 dc
.caret_chars
[0] = 'A';
2828 = make_location (linemap_position_for_column (line_table
, 8),
2829 linemap_position_for_column (line_table
, 7),
2830 linemap_position_for_column (line_table
, 9));
2831 dc
.caret_chars
[1] = 'B';
2834 = make_location (linemap_position_for_column (line_table
, 13),
2835 linemap_position_for_column (line_table
, 11),
2836 linemap_position_for_column (line_table
, 15));
2837 dc
.caret_chars
[2] = 'C';
2839 rich_location
richloc (line_table
, foo
);
2840 richloc
.add_range (bar
, SHOW_RANGE_WITH_CARET
);
2841 richloc
.add_range (field
, SHOW_RANGE_WITH_CARET
);
2842 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2844 " foo = bar.field;\n"
2846 pp_formatted_text (dc
.printer
));
2849 /* Insertion fix-it hint: adding an "&" to the front of "bar.field". */
2852 test_one_liner_fixit_insert_before ()
2854 test_diagnostic_context dc
;
2855 location_t caret
= linemap_position_for_column (line_table
, 7);
2856 rich_location
richloc (line_table
, caret
);
2857 richloc
.add_fixit_insert_before ("&");
2858 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2860 " foo = bar.field;\n"
2863 pp_formatted_text (dc
.printer
));
2866 /* Insertion fix-it hint: adding a "[0]" after "foo". */
2869 test_one_liner_fixit_insert_after ()
2871 test_diagnostic_context dc
;
2872 location_t start
= linemap_position_for_column (line_table
, 1);
2873 location_t finish
= linemap_position_for_column (line_table
, 3);
2874 location_t foo
= make_location (start
, start
, finish
);
2875 rich_location
richloc (line_table
, foo
);
2876 richloc
.add_fixit_insert_after ("[0]");
2877 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2879 " foo = bar.field;\n"
2882 pp_formatted_text (dc
.printer
));
2885 /* Removal fix-it hint: removal of the ".field".
2886 Also verify the interaction of pp_set_prefix with rulers and
2890 test_one_liner_fixit_remove ()
2892 location_t start
= linemap_position_for_column (line_table
, 10);
2893 location_t finish
= linemap_position_for_column (line_table
, 15);
2894 location_t dot
= make_location (start
, start
, finish
);
2895 rich_location
richloc (line_table
, dot
);
2896 richloc
.add_fixit_remove ();
2900 test_diagnostic_context dc
;
2901 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2903 " foo = bar.field;\n"
2906 pp_formatted_text (dc
.printer
));
2909 /* Test of adding a prefix. */
2911 test_diagnostic_context dc
;
2912 pp_prefixing_rule (dc
.printer
) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE
;
2913 pp_set_prefix (dc
.printer
, xstrdup ("TEST PREFIX:"));
2914 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2916 "TEST PREFIX: foo = bar.field;\n"
2917 "TEST PREFIX: ^~~~~~\n"
2918 "TEST PREFIX: ------\n",
2919 pp_formatted_text (dc
.printer
));
2922 /* Normal, with ruler. */
2924 test_diagnostic_context dc
;
2925 dc
.show_ruler_p
= true;
2926 dc
.caret_max_width
= 104;
2927 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2929 " 0 0 0 0 0 0 0 0 0 1 \n"
2930 " 1 2 3 4 5 6 7 8 9 0 \n"
2931 " 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234\n"
2932 " foo = bar.field;\n"
2935 pp_formatted_text (dc
.printer
));
2938 /* Test of adding a prefix, with ruler. */
2940 test_diagnostic_context dc
;
2941 dc
.show_ruler_p
= true;
2942 dc
.caret_max_width
= 50;
2943 pp_prefixing_rule (dc
.printer
) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE
;
2944 pp_set_prefix (dc
.printer
, xstrdup ("TEST PREFIX:"));
2945 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2947 "TEST PREFIX: 1 2 3 4 5\n"
2948 "TEST PREFIX: 12345678901234567890123456789012345678901234567890\n"
2949 "TEST PREFIX: foo = bar.field;\n"
2950 "TEST PREFIX: ^~~~~~\n"
2951 "TEST PREFIX: ------\n",
2952 pp_formatted_text (dc
.printer
));
2955 /* Test of adding a prefix, with ruler and line numbers. */
2957 test_diagnostic_context dc
;
2958 dc
.show_ruler_p
= true;
2959 dc
.caret_max_width
= 50;
2960 dc
.show_line_numbers_p
= true;
2961 pp_prefixing_rule (dc
.printer
) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE
;
2962 pp_set_prefix (dc
.printer
, xstrdup ("TEST PREFIX:"));
2963 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2965 "TEST PREFIX: | 1 2 3 4 5\n"
2966 "TEST PREFIX: | 12345678901234567890123456789012345678901234567890\n"
2967 "TEST PREFIX: 1 | foo = bar.field;\n"
2968 "TEST PREFIX: | ^~~~~~\n"
2969 "TEST PREFIX: | ------\n",
2970 pp_formatted_text (dc
.printer
));
2974 /* Replace fix-it hint: replacing "field" with "m_field". */
2977 test_one_liner_fixit_replace ()
2979 test_diagnostic_context dc
;
2980 location_t start
= linemap_position_for_column (line_table
, 11);
2981 location_t finish
= linemap_position_for_column (line_table
, 15);
2982 location_t field
= make_location (start
, start
, finish
);
2983 rich_location
richloc (line_table
, field
);
2984 richloc
.add_fixit_replace ("m_field");
2985 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
2987 " foo = bar.field;\n"
2990 pp_formatted_text (dc
.printer
));
2993 /* Replace fix-it hint: replacing "field" with "m_field",
2994 but where the caret was elsewhere. */
2997 test_one_liner_fixit_replace_non_equal_range ()
2999 test_diagnostic_context dc
;
3000 location_t equals
= linemap_position_for_column (line_table
, 5);
3001 location_t start
= linemap_position_for_column (line_table
, 11);
3002 location_t finish
= linemap_position_for_column (line_table
, 15);
3003 rich_location
richloc (line_table
, equals
);
3005 range
.m_start
= start
;
3006 range
.m_finish
= finish
;
3007 richloc
.add_fixit_replace (range
, "m_field");
3008 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3009 /* The replacement range is not indicated in the annotation line, so
3010 it should be indicated via an additional underline. */
3012 " foo = bar.field;\n"
3016 pp_formatted_text (dc
.printer
));
3019 /* Replace fix-it hint: replacing "field" with "m_field",
3020 where the caret was elsewhere, but where a secondary range
3021 exactly covers "field". */
3024 test_one_liner_fixit_replace_equal_secondary_range ()
3026 test_diagnostic_context dc
;
3027 location_t equals
= linemap_position_for_column (line_table
, 5);
3028 location_t start
= linemap_position_for_column (line_table
, 11);
3029 location_t finish
= linemap_position_for_column (line_table
, 15);
3030 rich_location
richloc (line_table
, equals
);
3031 location_t field
= make_location (start
, start
, finish
);
3032 richloc
.add_range (field
);
3033 richloc
.add_fixit_replace (field
, "m_field");
3034 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3035 /* The replacement range is indicated in the annotation line,
3036 so it shouldn't be indicated via an additional underline. */
3038 " foo = bar.field;\n"
3041 pp_formatted_text (dc
.printer
));
3044 /* Verify that we can use ad-hoc locations when adding fixits to a
3048 test_one_liner_fixit_validation_adhoc_locations ()
3050 /* Generate a range that's too long to be packed, so must
3051 be stored as an ad-hoc location (given the defaults
3052 of 5 bits or 0 bits of packed range); 41 columns > 2**5. */
3053 const location_t c7
= linemap_position_for_column (line_table
, 7);
3054 const location_t c47
= linemap_position_for_column (line_table
, 47);
3055 const location_t loc
= make_location (c7
, c7
, c47
);
3057 if (c47
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3060 ASSERT_TRUE (IS_ADHOC_LOC (loc
));
3064 rich_location
richloc (line_table
, loc
);
3065 richloc
.add_fixit_insert_before (loc
, "test");
3066 /* It should not have been discarded by the validator. */
3067 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3069 test_diagnostic_context dc
;
3070 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3072 " foo = bar.field;\n"
3075 pp_formatted_text (dc
.printer
));
3080 rich_location
richloc (line_table
, loc
);
3081 source_range range
= source_range::from_locations (loc
, c47
);
3082 richloc
.add_fixit_remove (range
);
3083 /* It should not have been discarded by the validator. */
3084 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3086 test_diagnostic_context dc
;
3087 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3089 " foo = bar.field;\n"
3091 " -----------------------------------------\n",
3092 pp_formatted_text (dc
.printer
));
3097 rich_location
richloc (line_table
, loc
);
3098 source_range range
= source_range::from_locations (loc
, c47
);
3099 richloc
.add_fixit_replace (range
, "test");
3100 /* It should not have been discarded by the validator. */
3101 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3103 test_diagnostic_context dc
;
3104 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3106 " foo = bar.field;\n"
3109 pp_formatted_text (dc
.printer
));
3113 /* Test of consolidating insertions at the same location. */
3116 test_one_liner_many_fixits_1 ()
3118 test_diagnostic_context dc
;
3119 location_t equals
= linemap_position_for_column (line_table
, 5);
3120 rich_location
richloc (line_table
, equals
);
3121 for (int i
= 0; i
< 19; i
++)
3122 richloc
.add_fixit_insert_before ("a");
3123 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3124 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3126 " foo = bar.field;\n"
3128 " aaaaaaaaaaaaaaaaaaa\n",
3129 pp_formatted_text (dc
.printer
));
3132 /* Ensure that we can add an arbitrary number of fix-it hints to a
3133 rich_location, even if they are not consolidated. */
3136 test_one_liner_many_fixits_2 ()
3138 test_diagnostic_context dc
;
3139 location_t equals
= linemap_position_for_column (line_table
, 5);
3140 rich_location
richloc (line_table
, equals
);
3141 for (int i
= 0; i
< 19; i
++)
3143 location_t loc
= linemap_position_for_column (line_table
, i
* 2);
3144 richloc
.add_fixit_insert_before (loc
, "a");
3146 ASSERT_EQ (19, richloc
.get_num_fixit_hints ());
3147 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3149 " foo = bar.field;\n"
3151 "a a a a a a a a a a a a a a a a a a a\n",
3152 pp_formatted_text (dc
.printer
));
3155 /* Test of labeling the ranges within a rich_location. */
3158 test_one_liner_labels ()
3161 = make_location (linemap_position_for_column (line_table
, 1),
3162 linemap_position_for_column (line_table
, 1),
3163 linemap_position_for_column (line_table
, 3));
3165 = make_location (linemap_position_for_column (line_table
, 7),
3166 linemap_position_for_column (line_table
, 7),
3167 linemap_position_for_column (line_table
, 9));
3169 = make_location (linemap_position_for_column (line_table
, 11),
3170 linemap_position_for_column (line_table
, 11),
3171 linemap_position_for_column (line_table
, 15));
3173 /* Example where all the labels fit on one line. */
3175 text_range_label
label0 ("0");
3176 text_range_label
label1 ("1");
3177 text_range_label
label2 ("2");
3178 gcc_rich_location
richloc (foo
, &label0
);
3179 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
3180 richloc
.add_range (field
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
3183 test_diagnostic_context dc
;
3184 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3186 " foo = bar.field;\n"
3190 pp_formatted_text (dc
.printer
));
3193 /* Verify that we can disable label-printing. */
3195 test_diagnostic_context dc
;
3196 dc
.show_labels_p
= false;
3197 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3199 " foo = bar.field;\n"
3201 pp_formatted_text (dc
.printer
));
3205 /* Example where the labels need extra lines. */
3207 text_range_label
label0 ("label 0");
3208 text_range_label
label1 ("label 1");
3209 text_range_label
label2 ("label 2");
3210 gcc_rich_location
richloc (foo
, &label0
);
3211 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
3212 richloc
.add_range (field
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
3214 test_diagnostic_context dc
;
3215 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3217 " foo = bar.field;\n"
3223 pp_formatted_text (dc
.printer
));
3226 /* Example of boundary conditions: label 0 and 1 have just enough clearance,
3227 but label 1 just touches label 2. */
3229 text_range_label
label0 ("aaaaa");
3230 text_range_label
label1 ("bbbb");
3231 text_range_label
label2 ("c");
3232 gcc_rich_location
richloc (foo
, &label0
);
3233 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
3234 richloc
.add_range (field
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
3236 test_diagnostic_context dc
;
3237 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3239 " foo = bar.field;\n"
3244 pp_formatted_text (dc
.printer
));
3247 /* Example of out-of-order ranges (thus requiring a sort). */
3249 text_range_label
label0 ("0");
3250 text_range_label
label1 ("1");
3251 text_range_label
label2 ("2");
3252 gcc_rich_location
richloc (field
, &label0
);
3253 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
3254 richloc
.add_range (foo
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
3256 test_diagnostic_context dc
;
3257 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3259 " foo = bar.field;\n"
3263 pp_formatted_text (dc
.printer
));
3266 /* Ensure we don't ICE if multiple ranges with labels are on
3269 text_range_label
label0 ("label 0");
3270 text_range_label
label1 ("label 1");
3271 text_range_label
label2 ("label 2");
3272 gcc_rich_location
richloc (bar
, &label0
);
3273 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
3274 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
3276 test_diagnostic_context dc
;
3277 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3279 " foo = bar.field;\n"
3285 pp_formatted_text (dc
.printer
));
3288 /* Example of out-of-order ranges (thus requiring a sort), where
3289 they overlap, and there are multiple ranges on the same point. */
3291 text_range_label
label_0a ("label 0a");
3292 text_range_label
label_1a ("label 1a");
3293 text_range_label
label_2a ("label 2a");
3294 text_range_label
label_0b ("label 0b");
3295 text_range_label
label_1b ("label 1b");
3296 text_range_label
label_2b ("label 2b");
3297 text_range_label
label_0c ("label 0c");
3298 text_range_label
label_1c ("label 1c");
3299 text_range_label
label_2c ("label 2c");
3300 gcc_rich_location
richloc (field
, &label_0a
);
3301 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label_1a
);
3302 richloc
.add_range (foo
, SHOW_RANGE_WITHOUT_CARET
, &label_2a
);
3304 richloc
.add_range (field
, SHOW_RANGE_WITHOUT_CARET
, &label_0b
);
3305 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label_1b
);
3306 richloc
.add_range (foo
, SHOW_RANGE_WITHOUT_CARET
, &label_2b
);
3308 richloc
.add_range (field
, SHOW_RANGE_WITHOUT_CARET
, &label_0c
);
3309 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label_1c
);
3310 richloc
.add_range (foo
, SHOW_RANGE_WITHOUT_CARET
, &label_2c
);
3312 test_diagnostic_context dc
;
3313 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3315 " foo = bar.field;\n"
3327 pp_formatted_text (dc
.printer
));
3330 /* Verify that a NULL result from range_label::get_text is
3331 handled gracefully. */
3333 text_range_label
label (NULL
);
3334 gcc_rich_location
richloc (bar
, &label
);
3336 test_diagnostic_context dc
;
3337 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3339 " foo = bar.field;\n"
3341 pp_formatted_text (dc
.printer
));
3344 /* TODO: example of formatted printing (needs to be in
3345 gcc-rich-location.c due to Makefile.in issues). */
3348 /* Run the various one-liner tests. */
3351 test_diagnostic_show_locus_one_liner (const line_table_case
&case_
)
3353 /* Create a tempfile and write some text to it.
3354 ....................0000000001111111.
3355 ....................1234567890123456. */
3356 const char *content
= "foo = bar.field;\n";
3357 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
3358 line_table_test
ltt (case_
);
3360 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 1);
3362 location_t line_end
= linemap_position_for_column (line_table
, 16);
3364 /* Don't attempt to run the tests if column data might be unavailable. */
3365 if (line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3368 ASSERT_STREQ (tmp
.get_filename (), LOCATION_FILE (line_end
));
3369 ASSERT_EQ (1, LOCATION_LINE (line_end
));
3370 ASSERT_EQ (16, LOCATION_COLUMN (line_end
));
3372 test_one_liner_simple_caret ();
3373 test_one_liner_caret_and_range ();
3374 test_one_liner_multiple_carets_and_ranges ();
3375 test_one_liner_fixit_insert_before ();
3376 test_one_liner_fixit_insert_after ();
3377 test_one_liner_fixit_remove ();
3378 test_one_liner_fixit_replace ();
3379 test_one_liner_fixit_replace_non_equal_range ();
3380 test_one_liner_fixit_replace_equal_secondary_range ();
3381 test_one_liner_fixit_validation_adhoc_locations ();
3382 test_one_liner_many_fixits_1 ();
3383 test_one_liner_many_fixits_2 ();
3384 test_one_liner_labels ();
3387 /* Version of all one-liner tests exercising multibyte awareness. For
3388 simplicity we stick to using two multibyte characters in the test, U+1F602
3389 == "\xf0\x9f\x98\x82", which uses 4 bytes and 2 display columns, and U+03C0
3390 == "\xcf\x80", which uses 2 bytes and 1 display column. Note: all of the
3391 below asserts would be easier to read if we used UTF-8 directly in the
3392 string constants, but it seems better not to demand the host compiler
3393 support this, when it isn't otherwise necessary. Instead, whenever an
3394 extended character appears in a string, we put a line break after it so that
3395 all succeeding characters can appear visually at the correct display column.
3397 All of these work on the following 1-line source file:
3399 .0000000001111111111222222 display
3400 .1234567890123456789012345 columns
3401 "SS_foo = P_bar.SS_fieldP;\n"
3402 .0000000111111111222222223 byte
3403 .1356789012456789134567891 columns
3405 which is set up by test_diagnostic_show_locus_one_liner and calls
3406 them. Here SS represents the two display columns for the U+1F602 emoji and
3407 P represents the one display column for the U+03C0 pi symbol. */
3412 test_one_liner_simple_caret_utf8 ()
3414 test_diagnostic_context dc
;
3415 location_t caret
= linemap_position_for_column (line_table
, 18);
3416 rich_location
richloc (line_table
, caret
);
3417 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3421 "_bar.\xf0\x9f\x98\x82"
3425 pp_formatted_text (dc
.printer
));
3428 /* Caret and range. */
3430 test_one_liner_caret_and_range_utf8 ()
3432 test_diagnostic_context dc
;
3433 location_t caret
= linemap_position_for_column (line_table
, 18);
3434 location_t start
= linemap_position_for_column (line_table
, 12);
3435 location_t finish
= linemap_position_for_column (line_table
, 30);
3436 location_t loc
= make_location (caret
, start
, finish
);
3437 rich_location
richloc (line_table
, loc
);
3438 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3442 "_bar.\xf0\x9f\x98\x82"
3445 " ~~~~~^~~~~~~~~~\n",
3446 pp_formatted_text (dc
.printer
));
3449 /* Multiple ranges and carets. */
3452 test_one_liner_multiple_carets_and_ranges_utf8 ()
3454 test_diagnostic_context dc
;
3456 = make_location (linemap_position_for_column (line_table
, 7),
3457 linemap_position_for_column (line_table
, 1),
3458 linemap_position_for_column (line_table
, 8));
3459 dc
.caret_chars
[0] = 'A';
3462 = make_location (linemap_position_for_column (line_table
, 16),
3463 linemap_position_for_column (line_table
, 12),
3464 linemap_position_for_column (line_table
, 17));
3465 dc
.caret_chars
[1] = 'B';
3468 = make_location (linemap_position_for_column (line_table
, 26),
3469 linemap_position_for_column (line_table
, 19),
3470 linemap_position_for_column (line_table
, 30));
3471 dc
.caret_chars
[2] = 'C';
3472 rich_location
richloc (line_table
, foo
);
3473 richloc
.add_range (bar
, SHOW_RANGE_WITH_CARET
);
3474 richloc
.add_range (field
, SHOW_RANGE_WITH_CARET
);
3475 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3479 "_bar.\xf0\x9f\x98\x82"
3482 " ~~~~A~ ~~~B~ ~~~~~C~~~\n",
3483 pp_formatted_text (dc
.printer
));
3486 /* Insertion fix-it hint: adding an "&" to the front of "P_bar.field". */
3489 test_one_liner_fixit_insert_before_utf8 ()
3491 test_diagnostic_context dc
;
3492 location_t caret
= linemap_position_for_column (line_table
, 12);
3493 rich_location
richloc (line_table
, caret
);
3494 richloc
.add_fixit_insert_before ("&");
3495 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3499 "_bar.\xf0\x9f\x98\x82"
3504 pp_formatted_text (dc
.printer
));
3507 /* Insertion fix-it hint: adding a "[0]" after "SS_foo". */
3510 test_one_liner_fixit_insert_after_utf8 ()
3512 test_diagnostic_context dc
;
3513 location_t start
= linemap_position_for_column (line_table
, 1);
3514 location_t finish
= linemap_position_for_column (line_table
, 8);
3515 location_t foo
= make_location (start
, start
, finish
);
3516 rich_location
richloc (line_table
, foo
);
3517 richloc
.add_fixit_insert_after ("[0]");
3518 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3522 "_bar.\xf0\x9f\x98\x82"
3527 pp_formatted_text (dc
.printer
));
3530 /* Removal fix-it hint: removal of the ".SS_fieldP". */
3533 test_one_liner_fixit_remove_utf8 ()
3535 test_diagnostic_context dc
;
3536 location_t start
= linemap_position_for_column (line_table
, 18);
3537 location_t finish
= linemap_position_for_column (line_table
, 30);
3538 location_t dot
= make_location (start
, start
, finish
);
3539 rich_location
richloc (line_table
, dot
);
3540 richloc
.add_fixit_remove ();
3541 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3545 "_bar.\xf0\x9f\x98\x82"
3550 pp_formatted_text (dc
.printer
));
3553 /* Replace fix-it hint: replacing "SS_fieldP" with "m_SSfieldP". */
3556 test_one_liner_fixit_replace_utf8 ()
3558 test_diagnostic_context dc
;
3559 location_t start
= linemap_position_for_column (line_table
, 19);
3560 location_t finish
= linemap_position_for_column (line_table
, 30);
3561 location_t field
= make_location (start
, start
, finish
);
3562 rich_location
richloc (line_table
, field
);
3563 richloc
.add_fixit_replace ("m_\xf0\x9f\x98\x82_field\xcf\x80");
3564 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3568 "_bar.\xf0\x9f\x98\x82"
3572 " m_\xf0\x9f\x98\x82"
3574 pp_formatted_text (dc
.printer
));
3577 /* Replace fix-it hint: replacing "SS_fieldP" with "m_SSfieldP",
3578 but where the caret was elsewhere. */
3581 test_one_liner_fixit_replace_non_equal_range_utf8 ()
3583 test_diagnostic_context dc
;
3584 location_t equals
= linemap_position_for_column (line_table
, 10);
3585 location_t start
= linemap_position_for_column (line_table
, 19);
3586 location_t finish
= linemap_position_for_column (line_table
, 30);
3587 rich_location
richloc (line_table
, equals
);
3589 range
.m_start
= start
;
3590 range
.m_finish
= finish
;
3591 richloc
.add_fixit_replace (range
, "m_\xf0\x9f\x98\x82_field\xcf\x80");
3592 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3593 /* The replacement range is not indicated in the annotation line, so
3594 it should be indicated via an additional underline. */
3598 "_bar.\xf0\x9f\x98\x82"
3603 " m_\xf0\x9f\x98\x82"
3605 pp_formatted_text (dc
.printer
));
3608 /* Replace fix-it hint: replacing "SS_fieldP" with "m_SSfieldP",
3609 where the caret was elsewhere, but where a secondary range
3610 exactly covers "field". */
3613 test_one_liner_fixit_replace_equal_secondary_range_utf8 ()
3615 test_diagnostic_context dc
;
3616 location_t equals
= linemap_position_for_column (line_table
, 10);
3617 location_t start
= linemap_position_for_column (line_table
, 19);
3618 location_t finish
= linemap_position_for_column (line_table
, 30);
3619 rich_location
richloc (line_table
, equals
);
3620 location_t field
= make_location (start
, start
, finish
);
3621 richloc
.add_range (field
);
3622 richloc
.add_fixit_replace (field
, "m_\xf0\x9f\x98\x82_field\xcf\x80");
3623 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3624 /* The replacement range is indicated in the annotation line,
3625 so it shouldn't be indicated via an additional underline. */
3629 "_bar.\xf0\x9f\x98\x82"
3633 " m_\xf0\x9f\x98\x82"
3635 pp_formatted_text (dc
.printer
));
3638 /* Verify that we can use ad-hoc locations when adding fixits to a
3642 test_one_liner_fixit_validation_adhoc_locations_utf8 ()
3644 /* Generate a range that's too long to be packed, so must
3645 be stored as an ad-hoc location (given the defaults
3646 of 5 bits or 0 bits of packed range); 41 columns > 2**5. */
3647 const location_t c12
= linemap_position_for_column (line_table
, 12);
3648 const location_t c52
= linemap_position_for_column (line_table
, 52);
3649 const location_t loc
= make_location (c12
, c12
, c52
);
3651 if (c52
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3654 ASSERT_TRUE (IS_ADHOC_LOC (loc
));
3658 rich_location
richloc (line_table
, loc
);
3659 richloc
.add_fixit_insert_before (loc
, "test");
3660 /* It should not have been discarded by the validator. */
3661 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3663 test_diagnostic_context dc
;
3664 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3668 "_bar.\xf0\x9f\x98\x82"
3671 " ^~~~~~~~~~~~~~~~ \n"
3673 pp_formatted_text (dc
.printer
));
3678 rich_location
richloc (line_table
, loc
);
3679 source_range range
= source_range::from_locations (loc
, c52
);
3680 richloc
.add_fixit_remove (range
);
3681 /* It should not have been discarded by the validator. */
3682 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3684 test_diagnostic_context dc
;
3685 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3689 "_bar.\xf0\x9f\x98\x82"
3692 " ^~~~~~~~~~~~~~~~ \n"
3693 " -------------------------------------\n",
3694 pp_formatted_text (dc
.printer
));
3699 rich_location
richloc (line_table
, loc
);
3700 source_range range
= source_range::from_locations (loc
, c52
);
3701 richloc
.add_fixit_replace (range
, "test");
3702 /* It should not have been discarded by the validator. */
3703 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3705 test_diagnostic_context dc
;
3706 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3710 "_bar.\xf0\x9f\x98\x82"
3713 " ^~~~~~~~~~~~~~~~ \n"
3715 pp_formatted_text (dc
.printer
));
3719 /* Test of consolidating insertions at the same location. */
3722 test_one_liner_many_fixits_1_utf8 ()
3724 test_diagnostic_context dc
;
3725 location_t equals
= linemap_position_for_column (line_table
, 10);
3726 rich_location
richloc (line_table
, equals
);
3727 for (int i
= 0; i
< 19; i
++)
3728 richloc
.add_fixit_insert_before (i
& 1 ? "@" : "\xcf\x80");
3729 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
3730 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3734 "_bar.\xf0\x9f\x98\x82"
3738 " \xcf\x80@\xcf\x80@\xcf\x80@\xcf\x80@\xcf\x80@"
3739 "\xcf\x80@\xcf\x80@\xcf\x80@\xcf\x80@\xcf\x80\n",
3740 pp_formatted_text (dc
.printer
));
3743 /* Ensure that we can add an arbitrary number of fix-it hints to a
3744 rich_location, even if they are not consolidated. */
3747 test_one_liner_many_fixits_2_utf8 ()
3749 test_diagnostic_context dc
;
3750 location_t equals
= linemap_position_for_column (line_table
, 10);
3751 rich_location
richloc (line_table
, equals
);
3752 const int nlocs
= 19;
3753 int locs
[nlocs
] = {1, 5, 7, 9, 11, 14, 16, 18, 23, 25, 27, 29, 32,
3754 34, 36, 38, 40, 42, 44};
3755 for (int i
= 0; i
!= nlocs
; ++i
)
3757 location_t loc
= linemap_position_for_column (line_table
, locs
[i
]);
3758 richloc
.add_fixit_insert_before (loc
, i
& 1 ? "@" : "\xcf\x80");
3761 ASSERT_EQ (nlocs
, richloc
.get_num_fixit_hints ());
3762 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3766 "_bar.\xf0\x9f\x98\x82"
3770 " \xcf\x80 @ \xcf\x80 @ \xcf\x80 @ \xcf\x80 @ \xcf\x80 @"
3771 " \xcf\x80 @ \xcf\x80 @ \xcf\x80 @ \xcf\x80 @ \xcf\x80\n",
3772 pp_formatted_text (dc
.printer
));
3775 /* Test of labeling the ranges within a rich_location. */
3778 test_one_liner_labels_utf8 ()
3781 = make_location (linemap_position_for_column (line_table
, 1),
3782 linemap_position_for_column (line_table
, 1),
3783 linemap_position_for_column (line_table
, 8));
3785 = make_location (linemap_position_for_column (line_table
, 12),
3786 linemap_position_for_column (line_table
, 12),
3787 linemap_position_for_column (line_table
, 17));
3789 = make_location (linemap_position_for_column (line_table
, 19),
3790 linemap_position_for_column (line_table
, 19),
3791 linemap_position_for_column (line_table
, 30));
3793 /* Example where all the labels fit on one line. */
3795 /* These three labels contain multibyte characters such that their byte
3796 lengths are respectively (12, 10, 18), but their display widths are only
3797 (6, 5, 9). All three fit on the line when considering the display
3798 widths, but not when considering the byte widths, so verify that we do
3799 indeed put them all on one line. */
3800 text_range_label label0
3801 ("\xcf\x80\xcf\x80\xcf\x80\xcf\x80\xcf\x80\xcf\x80");
3802 text_range_label label1
3803 ("\xf0\x9f\x98\x82\xf0\x9f\x98\x82\xcf\x80");
3804 text_range_label label2
3805 ("\xf0\x9f\x98\x82\xcf\x80\xf0\x9f\x98\x82\xf0\x9f\x98\x82\xcf\x80"
3807 gcc_rich_location
richloc (foo
, &label0
);
3808 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
3809 richloc
.add_range (field
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
3812 test_diagnostic_context dc
;
3813 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3817 "_bar.\xf0\x9f\x98\x82"
3820 " ^~~~~~ ~~~~~ ~~~~~~~~~\n"
3822 " \xcf\x80\xcf\x80\xcf\x80\xcf\x80\xcf\x80\xcf\x80"
3823 " \xf0\x9f\x98\x82\xf0\x9f\x98\x82\xcf\x80"
3824 " \xf0\x9f\x98\x82\xcf\x80\xf0\x9f\x98\x82"
3825 "\xf0\x9f\x98\x82\xcf\x80\xcf\x80\n",
3826 pp_formatted_text (dc
.printer
));
3831 /* Example where the labels need extra lines. */
3833 text_range_label
label0 ("label 0\xf0\x9f\x98\x82");
3834 text_range_label
label1 ("label 1\xcf\x80");
3835 text_range_label
label2 ("label 2\xcf\x80");
3836 gcc_rich_location
richloc (foo
, &label0
);
3837 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
3838 richloc
.add_range (field
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
3840 test_diagnostic_context dc
;
3841 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3846 "_bar.\xf0\x9f\x98\x82"
3849 " ^~~~~~ ~~~~~ ~~~~~~~~~\n"
3851 " | | label 2\xcf\x80\n"
3852 " | label 1\xcf\x80\n"
3853 " label 0\xf0\x9f\x98\x82\n",
3854 pp_formatted_text (dc
.printer
));
3857 /* Example of boundary conditions: label 0 and 1 have just enough clearance,
3858 but label 1 just touches label 2. */
3860 text_range_label
label0 ("aaaaa\xf0\x9f\x98\x82\xcf\x80");
3861 text_range_label
label1 ("bb\xf0\x9f\x98\x82\xf0\x9f\x98\x82");
3862 text_range_label
label2 ("c");
3863 gcc_rich_location
richloc (foo
, &label0
);
3864 richloc
.add_range (bar
, SHOW_RANGE_WITHOUT_CARET
, &label1
);
3865 richloc
.add_range (field
, SHOW_RANGE_WITHOUT_CARET
, &label2
);
3867 test_diagnostic_context dc
;
3868 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3872 "_bar.\xf0\x9f\x98\x82"
3875 " ^~~~~~ ~~~~~ ~~~~~~~~~\n"
3878 " aaaaa\xf0\x9f\x98\x82\xcf\x80"
3879 " bb\xf0\x9f\x98\x82\xf0\x9f\x98\x82\n",
3880 pp_formatted_text (dc
.printer
));
3884 /* Run the various one-liner tests. */
3887 test_diagnostic_show_locus_one_liner_utf8 (const line_table_case
&case_
)
3889 /* Create a tempfile and write some text to it. */
3892 0000000000000000000000011111111111111111111111111111112222222222222
3893 1111111122222222345678900000000123456666666677777777890123444444445 */
3894 = "\xf0\x9f\x98\x82_foo = \xcf\x80_bar.\xf0\x9f\x98\x82_field\xcf\x80;\n";
3895 /* 0000000000000000000001111111111111111111222222222222222222222233333
3896 1111222233334444567890122223333456789999000011112222345678999900001
3898 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
3899 line_table_test
ltt (case_
);
3901 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 1);
3903 location_t line_end
= linemap_position_for_column (line_table
, 31);
3905 /* Don't attempt to run the tests if column data might be unavailable. */
3906 if (line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3909 ASSERT_STREQ (tmp
.get_filename (), LOCATION_FILE (line_end
));
3910 ASSERT_EQ (1, LOCATION_LINE (line_end
));
3911 ASSERT_EQ (31, LOCATION_COLUMN (line_end
));
3913 char_span lspan
= location_get_source_line (tmp
.get_filename (), 1);
3914 ASSERT_EQ (25, cpp_display_width (lspan
.get_buffer (), lspan
.length ()));
3915 ASSERT_EQ (25, location_compute_display_column (expand_location (line_end
)));
3917 test_one_liner_simple_caret_utf8 ();
3918 test_one_liner_caret_and_range_utf8 ();
3919 test_one_liner_multiple_carets_and_ranges_utf8 ();
3920 test_one_liner_fixit_insert_before_utf8 ();
3921 test_one_liner_fixit_insert_after_utf8 ();
3922 test_one_liner_fixit_remove_utf8 ();
3923 test_one_liner_fixit_replace_utf8 ();
3924 test_one_liner_fixit_replace_non_equal_range_utf8 ();
3925 test_one_liner_fixit_replace_equal_secondary_range_utf8 ();
3926 test_one_liner_fixit_validation_adhoc_locations_utf8 ();
3927 test_one_liner_many_fixits_1_utf8 ();
3928 test_one_liner_many_fixits_2_utf8 ();
3929 test_one_liner_labels_utf8 ();
3932 /* Verify that gcc_rich_location::add_location_if_nearby works. */
3935 test_add_location_if_nearby (const line_table_case
&case_
)
3937 /* Create a tempfile and write some text to it.
3938 ...000000000111111111122222222223333333333.
3939 ...123456789012345678901234567890123456789. */
3941 = ("struct same_line { double x; double y; ;\n" /* line 1. */
3942 "struct different_line\n" /* line 2. */
3944 " double x;\n" /* line 4. */
3945 " double y;\n" /* line 5. */
3946 ";\n"); /* line 6. */
3947 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
3948 line_table_test
ltt (case_
);
3950 const line_map_ordinary
*ord_map
3951 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
3952 tmp
.get_filename (), 0));
3954 linemap_line_start (line_table
, 1, 100);
3956 const location_t final_line_end
3957 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 7);
3959 /* Don't attempt to run the tests if column data might be unavailable. */
3960 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
3963 /* Test of add_location_if_nearby on the same line as the
3964 primary location. */
3966 const location_t missing_close_brace_1_39
3967 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 39);
3968 const location_t matching_open_brace_1_18
3969 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 18);
3970 gcc_rich_location
richloc (missing_close_brace_1_39
);
3971 bool added
= richloc
.add_location_if_nearby (matching_open_brace_1_18
);
3972 ASSERT_TRUE (added
);
3973 ASSERT_EQ (2, richloc
.get_num_locations ());
3974 test_diagnostic_context dc
;
3975 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
3977 " struct same_line { double x; double y; ;\n"
3979 pp_formatted_text (dc
.printer
));
3982 /* Test of add_location_if_nearby on a different line to the
3983 primary location. */
3985 const location_t missing_close_brace_6_1
3986 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 1);
3987 const location_t matching_open_brace_3_1
3988 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 1);
3989 gcc_rich_location
richloc (missing_close_brace_6_1
);
3990 bool added
= richloc
.add_location_if_nearby (matching_open_brace_3_1
);
3991 ASSERT_FALSE (added
);
3992 ASSERT_EQ (1, richloc
.get_num_locations ());
3996 /* Verify that we print fixits even if they only affect lines
3997 outside those covered by the ranges in the rich_location. */
4000 test_diagnostic_show_locus_fixit_lines (const line_table_case
&case_
)
4002 /* Create a tempfile and write some text to it.
4003 ...000000000111111111122222222223333333333.
4004 ...123456789012345678901234567890123456789. */
4006 = ("struct point { double x; double y; };\n" /* line 1. */
4007 "struct point origin = {x: 0.0,\n" /* line 2. */
4008 " y\n" /* line 3. */
4011 " : 0.0};\n"); /* line 6. */
4012 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
4013 line_table_test
ltt (case_
);
4015 const line_map_ordinary
*ord_map
4016 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
4017 tmp
.get_filename (), 0));
4019 linemap_line_start (line_table
, 1, 100);
4021 const location_t final_line_end
4022 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 36);
4024 /* Don't attempt to run the tests if column data might be unavailable. */
4025 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
4028 /* A pair of tests for modernizing the initializers to C99-style. */
4030 /* The one-liner case (line 2). */
4032 test_diagnostic_context dc
;
4034 = linemap_position_for_line_and_column (line_table
, ord_map
, 2, 24);
4035 const location_t colon
4036 = linemap_position_for_line_and_column (line_table
, ord_map
, 2, 25);
4037 rich_location
richloc (line_table
, colon
);
4038 richloc
.add_fixit_insert_before (x
, ".");
4039 richloc
.add_fixit_replace (colon
, "=");
4040 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4042 " struct point origin = {x: 0.0,\n"
4045 pp_formatted_text (dc
.printer
));
4048 /* The multiline case. The caret for the rich_location is on line 6;
4049 verify that insertion fixit on line 3 is still printed (and that
4050 span starts are printed due to the gap between the span at line 3
4051 and that at line 6). */
4053 test_diagnostic_context dc
;
4055 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 24);
4056 const location_t colon
4057 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 25);
4058 rich_location
richloc (line_table
, colon
);
4059 richloc
.add_fixit_insert_before (y
, ".");
4060 richloc
.add_fixit_replace (colon
, "=");
4061 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4070 pp_formatted_text (dc
.printer
));
4073 /* As above, but verify the behavior of multiple line spans
4074 with line-numbering enabled. */
4077 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 24);
4078 const location_t colon
4079 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 25);
4080 rich_location
richloc (line_table
, colon
);
4081 richloc
.add_fixit_insert_before (y
, ".");
4082 richloc
.add_fixit_replace (colon
, "=");
4083 test_diagnostic_context dc
;
4084 dc
.show_line_numbers_p
= true;
4085 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4093 pp_formatted_text (dc
.printer
));
4098 /* Verify that fix-it hints are appropriately consolidated.
4100 If any fix-it hints in a rich_location involve locations beyond
4101 LINE_MAP_MAX_LOCATION_WITH_COLS, then we can't reliably apply
4102 the fix-it as a whole, so there should be none.
4104 Otherwise, verify that consecutive "replace" and "remove" fix-its
4105 are merged, and that other fix-its remain separate. */
4108 test_fixit_consolidation (const line_table_case
&case_
)
4110 line_table_test
ltt (case_
);
4112 linemap_add (line_table
, LC_ENTER
, false, "test.c", 1);
4114 const location_t c10
= linemap_position_for_column (line_table
, 10);
4115 const location_t c15
= linemap_position_for_column (line_table
, 15);
4116 const location_t c16
= linemap_position_for_column (line_table
, 16);
4117 const location_t c17
= linemap_position_for_column (line_table
, 17);
4118 const location_t c20
= linemap_position_for_column (line_table
, 20);
4119 const location_t c21
= linemap_position_for_column (line_table
, 21);
4120 const location_t caret
= c10
;
4122 /* Insert + insert. */
4124 rich_location
richloc (line_table
, caret
);
4125 richloc
.add_fixit_insert_before (c10
, "foo");
4126 richloc
.add_fixit_insert_before (c15
, "bar");
4128 if (c15
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
4129 /* Bogus column info for 2nd fixit, so no fixits. */
4130 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
4132 /* They should not have been merged. */
4133 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
4136 /* Insert + replace. */
4138 rich_location
richloc (line_table
, caret
);
4139 richloc
.add_fixit_insert_before (c10
, "foo");
4140 richloc
.add_fixit_replace (source_range::from_locations (c15
, c17
),
4143 if (c17
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
4144 /* Bogus column info for 2nd fixit, so no fixits. */
4145 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
4147 /* They should not have been merged. */
4148 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
4151 /* Replace + non-consecutive insert. */
4153 rich_location
richloc (line_table
, caret
);
4154 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
4156 richloc
.add_fixit_insert_before (c17
, "foo");
4158 if (c17
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
4159 /* Bogus column info for 2nd fixit, so no fixits. */
4160 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
4162 /* They should not have been merged. */
4163 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
4166 /* Replace + non-consecutive replace. */
4168 rich_location
richloc (line_table
, caret
);
4169 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
4171 richloc
.add_fixit_replace (source_range::from_locations (c17
, c20
),
4174 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
4175 /* Bogus column info for 2nd fixit, so no fixits. */
4176 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
4178 /* They should not have been merged. */
4179 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
4182 /* Replace + consecutive replace. */
4184 rich_location
richloc (line_table
, caret
);
4185 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
4187 richloc
.add_fixit_replace (source_range::from_locations (c16
, c20
),
4190 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
4191 /* Bogus column info for 2nd fixit, so no fixits. */
4192 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
4195 /* They should have been merged into a single "replace". */
4196 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
4197 const fixit_hint
*hint
= richloc
.get_fixit_hint (0);
4198 ASSERT_STREQ ("foobar", hint
->get_string ());
4199 ASSERT_EQ (c10
, hint
->get_start_loc ());
4200 ASSERT_EQ (c21
, hint
->get_next_loc ());
4204 /* Replace + consecutive removal. */
4206 rich_location
richloc (line_table
, caret
);
4207 richloc
.add_fixit_replace (source_range::from_locations (c10
, c15
),
4209 richloc
.add_fixit_remove (source_range::from_locations (c16
, c20
));
4211 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
4212 /* Bogus column info for 2nd fixit, so no fixits. */
4213 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
4216 /* They should have been merged into a single replace, with the
4217 range extended to cover that of the removal. */
4218 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
4219 const fixit_hint
*hint
= richloc
.get_fixit_hint (0);
4220 ASSERT_STREQ ("foo", hint
->get_string ());
4221 ASSERT_EQ (c10
, hint
->get_start_loc ());
4222 ASSERT_EQ (c21
, hint
->get_next_loc ());
4226 /* Consecutive removals. */
4228 rich_location
richloc (line_table
, caret
);
4229 richloc
.add_fixit_remove (source_range::from_locations (c10
, c15
));
4230 richloc
.add_fixit_remove (source_range::from_locations (c16
, c20
));
4232 if (c20
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
4233 /* Bogus column info for 2nd fixit, so no fixits. */
4234 ASSERT_EQ (0, richloc
.get_num_fixit_hints ());
4237 /* They should have been merged into a single "replace-with-empty". */
4238 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
4239 const fixit_hint
*hint
= richloc
.get_fixit_hint (0);
4240 ASSERT_STREQ ("", hint
->get_string ());
4241 ASSERT_EQ (c10
, hint
->get_start_loc ());
4242 ASSERT_EQ (c21
, hint
->get_next_loc ());
4247 /* Verify that the line_corrections machinery correctly prints
4248 overlapping fixit-hints. */
4251 test_overlapped_fixit_printing (const line_table_case
&case_
)
4253 /* Create a tempfile and write some text to it.
4254 ...000000000111111111122222222223333333333.
4255 ...123456789012345678901234567890123456789. */
4257 = (" foo *f = (foo *)ptr->field;\n");
4258 temp_source_file
tmp (SELFTEST_LOCATION
, ".C", content
);
4259 line_table_test
ltt (case_
);
4261 const line_map_ordinary
*ord_map
4262 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
4263 tmp
.get_filename (), 0));
4265 linemap_line_start (line_table
, 1, 100);
4267 const location_t final_line_end
4268 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 36);
4270 /* Don't attempt to run the tests if column data might be unavailable. */
4271 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
4274 /* A test for converting a C-style cast to a C++-style cast. */
4275 const location_t open_paren
4276 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 12);
4277 const location_t close_paren
4278 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 18);
4279 const location_t expr_start
4280 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 19);
4281 const location_t expr_finish
4282 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 28);
4283 const location_t expr
= make_location (expr_start
, expr_start
, expr_finish
);
4285 /* Various examples of fix-it hints that aren't themselves consolidated,
4286 but for which the *printing* may need consolidation. */
4288 /* Example where 3 fix-it hints are printed as one. */
4290 test_diagnostic_context dc
;
4291 rich_location
richloc (line_table
, expr
);
4292 richloc
.add_fixit_replace (open_paren
, "const_cast<");
4293 richloc
.add_fixit_replace (close_paren
, "> (");
4294 richloc
.add_fixit_insert_after (")");
4296 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4298 " foo *f = (foo *)ptr->field;\n"
4300 " -----------------\n"
4301 " const_cast<foo *> (ptr->field)\n",
4302 pp_formatted_text (dc
.printer
));
4304 /* Unit-test the line_corrections machinery. */
4305 ASSERT_EQ (3, richloc
.get_num_fixit_hints ());
4306 const fixit_hint
*hint_0
= richloc
.get_fixit_hint (0);
4307 ASSERT_EQ (column_range (12, 12), get_affected_range (hint_0
, CU_BYTES
));
4308 ASSERT_EQ (column_range (12, 12),
4309 get_affected_range (hint_0
, CU_DISPLAY_COLS
));
4310 ASSERT_EQ (column_range (12, 22), get_printed_columns (hint_0
));
4311 const fixit_hint
*hint_1
= richloc
.get_fixit_hint (1);
4312 ASSERT_EQ (column_range (18, 18), get_affected_range (hint_1
, CU_BYTES
));
4313 ASSERT_EQ (column_range (18, 18),
4314 get_affected_range (hint_1
, CU_DISPLAY_COLS
));
4315 ASSERT_EQ (column_range (18, 20), get_printed_columns (hint_1
));
4316 const fixit_hint
*hint_2
= richloc
.get_fixit_hint (2);
4317 ASSERT_EQ (column_range (29, 28), get_affected_range (hint_2
, CU_BYTES
));
4318 ASSERT_EQ (column_range (29, 28),
4319 get_affected_range (hint_2
, CU_DISPLAY_COLS
));
4320 ASSERT_EQ (column_range (29, 29), get_printed_columns (hint_2
));
4322 /* Add each hint in turn to a line_corrections instance,
4323 and verify that they are consolidated into one correction instance
4325 line_corrections
lc (tmp
.get_filename (), 1);
4327 /* The first replace hint by itself. */
4328 lc
.add_hint (hint_0
);
4329 ASSERT_EQ (1, lc
.m_corrections
.length ());
4330 ASSERT_EQ (column_range (12, 12), lc
.m_corrections
[0]->m_affected_bytes
);
4331 ASSERT_EQ (column_range (12, 12), lc
.m_corrections
[0]->m_affected_columns
);
4332 ASSERT_EQ (column_range (12, 22), lc
.m_corrections
[0]->m_printed_columns
);
4333 ASSERT_STREQ ("const_cast<", lc
.m_corrections
[0]->m_text
);
4335 /* After the second replacement hint, they are printed together
4336 as a replacement (along with the text between them). */
4337 lc
.add_hint (hint_1
);
4338 ASSERT_EQ (1, lc
.m_corrections
.length ());
4339 ASSERT_STREQ ("const_cast<foo *> (", lc
.m_corrections
[0]->m_text
);
4340 ASSERT_EQ (column_range (12, 18), lc
.m_corrections
[0]->m_affected_bytes
);
4341 ASSERT_EQ (column_range (12, 18), lc
.m_corrections
[0]->m_affected_columns
);
4342 ASSERT_EQ (column_range (12, 30), lc
.m_corrections
[0]->m_printed_columns
);
4344 /* After the final insertion hint, they are all printed together
4345 as a replacement (along with the text between them). */
4346 lc
.add_hint (hint_2
);
4347 ASSERT_STREQ ("const_cast<foo *> (ptr->field)",
4348 lc
.m_corrections
[0]->m_text
);
4349 ASSERT_EQ (1, lc
.m_corrections
.length ());
4350 ASSERT_EQ (column_range (12, 28), lc
.m_corrections
[0]->m_affected_bytes
);
4351 ASSERT_EQ (column_range (12, 28), lc
.m_corrections
[0]->m_affected_columns
);
4352 ASSERT_EQ (column_range (12, 41), lc
.m_corrections
[0]->m_printed_columns
);
4355 /* Example where two are consolidated during printing. */
4357 test_diagnostic_context dc
;
4358 rich_location
richloc (line_table
, expr
);
4359 richloc
.add_fixit_replace (open_paren
, "CAST (");
4360 richloc
.add_fixit_replace (close_paren
, ") (");
4361 richloc
.add_fixit_insert_after (")");
4363 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4365 " foo *f = (foo *)ptr->field;\n"
4370 pp_formatted_text (dc
.printer
));
4373 /* Example where none are consolidated during printing. */
4375 test_diagnostic_context dc
;
4376 rich_location
richloc (line_table
, expr
);
4377 richloc
.add_fixit_replace (open_paren
, "CST (");
4378 richloc
.add_fixit_replace (close_paren
, ") (");
4379 richloc
.add_fixit_insert_after (")");
4381 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4383 " foo *f = (foo *)ptr->field;\n"
4388 pp_formatted_text (dc
.printer
));
4391 /* Example of deletion fix-it hints. */
4393 test_diagnostic_context dc
;
4394 rich_location
richloc (line_table
, expr
);
4395 richloc
.add_fixit_insert_before (open_paren
, "(bar *)");
4396 source_range victim
= {open_paren
, close_paren
};
4397 richloc
.add_fixit_remove (victim
);
4399 /* This case is actually handled by fixit-consolidation,
4400 rather than by line_corrections. */
4401 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
4403 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4405 " foo *f = (foo *)ptr->field;\n"
4409 pp_formatted_text (dc
.printer
));
4412 /* Example of deletion fix-it hints that would overlap. */
4414 test_diagnostic_context dc
;
4415 rich_location
richloc (line_table
, expr
);
4416 richloc
.add_fixit_insert_before (open_paren
, "(longer *)");
4417 source_range victim
= {expr_start
, expr_finish
};
4418 richloc
.add_fixit_remove (victim
);
4420 /* These fixits are not consolidated. */
4421 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
4423 /* But the corrections are. */
4424 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4426 " foo *f = (foo *)ptr->field;\n"
4428 " -----------------\n"
4429 " (longer *)(foo *)\n",
4430 pp_formatted_text (dc
.printer
));
4433 /* Example of insertion fix-it hints that would overlap. */
4435 test_diagnostic_context dc
;
4436 rich_location
richloc (line_table
, expr
);
4437 richloc
.add_fixit_insert_before (open_paren
, "LONGER THAN THE CAST");
4438 richloc
.add_fixit_insert_after (close_paren
, "TEST");
4440 /* The first insertion is long enough that if printed naively,
4441 it would overlap with the second.
4442 Verify that they are printed as a single replacement. */
4443 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4445 " foo *f = (foo *)ptr->field;\n"
4448 " LONGER THAN THE CAST(foo *)TEST\n",
4449 pp_formatted_text (dc
.printer
));
4453 /* Multibyte-aware version of preceding tests. See comments above
4454 test_one_liner_simple_caret_utf8() too, we use the same two multibyte
4458 test_overlapped_fixit_printing_utf8 (const line_table_case
&case_
)
4460 /* Create a tempfile and write some text to it. */
4464 00000000000000000000000111111111111111111111111222222222222222223
4465 12344444444555555556789012344444444555555556789012345678999999990 */
4466 = " f\xf0\x9f\x98\x82 *f = (f\xf0\x9f\x98\x82 *)ptr->field\xcf\x80;\n";
4467 /* 00000000000000000000011111111111111111111112222222222333333333333
4468 12344445555666677778901234566667777888899990123456789012333344445
4471 temp_source_file
tmp (SELFTEST_LOCATION
, ".C", content
);
4472 line_table_test
ltt (case_
);
4474 const line_map_ordinary
*ord_map
4475 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
4476 tmp
.get_filename (), 0));
4478 linemap_line_start (line_table
, 1, 100);
4480 const location_t final_line_end
4481 = linemap_position_for_line_and_column (line_table
, ord_map
, 6, 50);
4483 /* Don't attempt to run the tests if column data might be unavailable. */
4484 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
4487 /* A test for converting a C-style cast to a C++-style cast. */
4488 const location_t open_paren
4489 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 14);
4490 const location_t close_paren
4491 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 22);
4492 const location_t expr_start
4493 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 23);
4494 const location_t expr_finish
4495 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 34);
4496 const location_t expr
= make_location (expr_start
, expr_start
, expr_finish
);
4498 /* Various examples of fix-it hints that aren't themselves consolidated,
4499 but for which the *printing* may need consolidation. */
4501 /* Example where 3 fix-it hints are printed as one. */
4503 test_diagnostic_context dc
;
4504 rich_location
richloc (line_table
, expr
);
4505 richloc
.add_fixit_replace (open_paren
, "const_cast<");
4506 richloc
.add_fixit_replace (close_paren
, "> (");
4507 richloc
.add_fixit_insert_after (")");
4509 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4511 " f\xf0\x9f\x98\x82"
4512 " *f = (f\xf0\x9f\x98\x82"
4513 " *)ptr->field\xcf\x80"
4516 " ------------------\n"
4517 " const_cast<f\xf0\x9f\x98\x82"
4518 " *> (ptr->field\xcf\x80"
4520 pp_formatted_text (dc
.printer
));
4522 /* Unit-test the line_corrections machinery. */
4523 ASSERT_EQ (3, richloc
.get_num_fixit_hints ());
4524 const fixit_hint
*hint_0
= richloc
.get_fixit_hint (0);
4525 ASSERT_EQ (column_range (14, 14), get_affected_range (hint_0
, CU_BYTES
));
4526 ASSERT_EQ (column_range (12, 12),
4527 get_affected_range (hint_0
, CU_DISPLAY_COLS
));
4528 ASSERT_EQ (column_range (12, 22), get_printed_columns (hint_0
));
4529 const fixit_hint
*hint_1
= richloc
.get_fixit_hint (1);
4530 ASSERT_EQ (column_range (22, 22), get_affected_range (hint_1
, CU_BYTES
));
4531 ASSERT_EQ (column_range (18, 18),
4532 get_affected_range (hint_1
, CU_DISPLAY_COLS
));
4533 ASSERT_EQ (column_range (18, 20), get_printed_columns (hint_1
));
4534 const fixit_hint
*hint_2
= richloc
.get_fixit_hint (2);
4535 ASSERT_EQ (column_range (35, 34), get_affected_range (hint_2
, CU_BYTES
));
4536 ASSERT_EQ (column_range (30, 29),
4537 get_affected_range (hint_2
, CU_DISPLAY_COLS
));
4538 ASSERT_EQ (column_range (30, 30), get_printed_columns (hint_2
));
4540 /* Add each hint in turn to a line_corrections instance,
4541 and verify that they are consolidated into one correction instance
4543 line_corrections
lc (tmp
.get_filename (), 1);
4545 /* The first replace hint by itself. */
4546 lc
.add_hint (hint_0
);
4547 ASSERT_EQ (1, lc
.m_corrections
.length ());
4548 ASSERT_EQ (column_range (14, 14), lc
.m_corrections
[0]->m_affected_bytes
);
4549 ASSERT_EQ (column_range (12, 12), lc
.m_corrections
[0]->m_affected_columns
);
4550 ASSERT_EQ (column_range (12, 22), lc
.m_corrections
[0]->m_printed_columns
);
4551 ASSERT_STREQ ("const_cast<", lc
.m_corrections
[0]->m_text
);
4553 /* After the second replacement hint, they are printed together
4554 as a replacement (along with the text between them). */
4555 lc
.add_hint (hint_1
);
4556 ASSERT_EQ (1, lc
.m_corrections
.length ());
4557 ASSERT_STREQ ("const_cast<f\xf0\x9f\x98\x82 *> (",
4558 lc
.m_corrections
[0]->m_text
);
4559 ASSERT_EQ (column_range (14, 22), lc
.m_corrections
[0]->m_affected_bytes
);
4560 ASSERT_EQ (column_range (12, 18), lc
.m_corrections
[0]->m_affected_columns
);
4561 ASSERT_EQ (column_range (12, 30), lc
.m_corrections
[0]->m_printed_columns
);
4563 /* After the final insertion hint, they are all printed together
4564 as a replacement (along with the text between them). */
4565 lc
.add_hint (hint_2
);
4566 ASSERT_STREQ ("const_cast<f\xf0\x9f\x98\x82 *> (ptr->field\xcf\x80)",
4567 lc
.m_corrections
[0]->m_text
);
4568 ASSERT_EQ (1, lc
.m_corrections
.length ());
4569 ASSERT_EQ (column_range (14, 34), lc
.m_corrections
[0]->m_affected_bytes
);
4570 ASSERT_EQ (column_range (12, 29), lc
.m_corrections
[0]->m_affected_columns
);
4571 ASSERT_EQ (column_range (12, 42), lc
.m_corrections
[0]->m_printed_columns
);
4574 /* Example where two are consolidated during printing. */
4576 test_diagnostic_context dc
;
4577 rich_location
richloc (line_table
, expr
);
4578 richloc
.add_fixit_replace (open_paren
, "CAST (");
4579 richloc
.add_fixit_replace (close_paren
, ") (");
4580 richloc
.add_fixit_insert_after (")");
4582 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4584 " f\xf0\x9f\x98\x82"
4585 " *f = (f\xf0\x9f\x98\x82"
4586 " *)ptr->field\xcf\x80"
4592 pp_formatted_text (dc
.printer
));
4595 /* Example where none are consolidated during printing. */
4597 test_diagnostic_context dc
;
4598 rich_location
richloc (line_table
, expr
);
4599 richloc
.add_fixit_replace (open_paren
, "CST (");
4600 richloc
.add_fixit_replace (close_paren
, ") (");
4601 richloc
.add_fixit_insert_after (")");
4603 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4605 " f\xf0\x9f\x98\x82"
4606 " *f = (f\xf0\x9f\x98\x82"
4607 " *)ptr->field\xcf\x80"
4613 pp_formatted_text (dc
.printer
));
4616 /* Example of deletion fix-it hints. */
4618 test_diagnostic_context dc
;
4619 rich_location
richloc (line_table
, expr
);
4620 richloc
.add_fixit_insert_before (open_paren
, "(bar\xf0\x9f\x98\x82 *)");
4621 source_range victim
= {open_paren
, close_paren
};
4622 richloc
.add_fixit_remove (victim
);
4624 /* This case is actually handled by fixit-consolidation,
4625 rather than by line_corrections. */
4626 ASSERT_EQ (1, richloc
.get_num_fixit_hints ());
4628 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4630 " f\xf0\x9f\x98\x82"
4631 " *f = (f\xf0\x9f\x98\x82"
4632 " *)ptr->field\xcf\x80"
4636 " (bar\xf0\x9f\x98\x82"
4638 pp_formatted_text (dc
.printer
));
4641 /* Example of deletion fix-it hints that would overlap. */
4643 test_diagnostic_context dc
;
4644 rich_location
richloc (line_table
, expr
);
4645 richloc
.add_fixit_insert_before (open_paren
, "(long\xf0\x9f\x98\x82 *)");
4646 source_range victim
= {expr_start
, expr_finish
};
4647 richloc
.add_fixit_remove (victim
);
4649 /* These fixits are not consolidated. */
4650 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
4652 /* But the corrections are. */
4653 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4655 " f\xf0\x9f\x98\x82"
4656 " *f = (f\xf0\x9f\x98\x82"
4657 " *)ptr->field\xcf\x80"
4660 " ------------------\n"
4661 " (long\xf0\x9f\x98\x82"
4662 " *)(f\xf0\x9f\x98\x82"
4664 pp_formatted_text (dc
.printer
));
4667 /* Example of insertion fix-it hints that would overlap. */
4669 test_diagnostic_context dc
;
4670 rich_location
richloc (line_table
, expr
);
4671 richloc
.add_fixit_insert_before
4672 (open_paren
, "L\xf0\x9f\x98\x82NGER THAN THE CAST");
4673 richloc
.add_fixit_insert_after (close_paren
, "TEST");
4675 /* The first insertion is long enough that if printed naively,
4676 it would overlap with the second.
4677 Verify that they are printed as a single replacement. */
4678 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4680 " f\xf0\x9f\x98\x82"
4681 " *f = (f\xf0\x9f\x98\x82"
4682 " *)ptr->field\xcf\x80"
4686 " L\xf0\x9f\x98\x82"
4687 "NGER THAN THE CAST(f\xf0\x9f\x98\x82"
4689 pp_formatted_text (dc
.printer
));
4693 /* Verify that the line_corrections machinery correctly prints
4694 overlapping fixit-hints that have been added in the wrong
4696 Adapted from PR c/81405 seen on gcc.dg/init-excess-1.c*/
4699 test_overlapped_fixit_printing_2 (const line_table_case
&case_
)
4701 /* Create a tempfile and write some text to it.
4702 ...000000000111111111122222222223333333333.
4703 ...123456789012345678901234567890123456789. */
4705 = ("int a5[][0][0] = { 1, 2 };\n");
4706 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", content
);
4707 line_table_test
ltt (case_
);
4709 const line_map_ordinary
*ord_map
4710 = linemap_check_ordinary (linemap_add (line_table
, LC_ENTER
, false,
4711 tmp
.get_filename (), 0));
4713 linemap_line_start (line_table
, 1, 100);
4715 const location_t final_line_end
4716 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 100);
4718 /* Don't attempt to run the tests if column data might be unavailable. */
4719 if (final_line_end
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
4722 const location_t col_1
4723 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 1);
4724 const location_t col_20
4725 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 20);
4726 const location_t col_21
4727 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 21);
4728 const location_t col_23
4729 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 23);
4730 const location_t col_25
4731 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 25);
4733 /* Two insertions, in the wrong order. */
4735 rich_location
richloc (line_table
, col_20
);
4736 richloc
.add_fixit_insert_before (col_23
, "{");
4737 richloc
.add_fixit_insert_before (col_21
, "}");
4739 /* These fixits should be accepted; they can't be consolidated. */
4740 ASSERT_EQ (2, richloc
.get_num_fixit_hints ());
4741 const fixit_hint
*hint_0
= richloc
.get_fixit_hint (0);
4742 ASSERT_EQ (column_range (23, 22), get_affected_range (hint_0
, CU_BYTES
));
4743 ASSERT_EQ (column_range (23, 23), get_printed_columns (hint_0
));
4744 const fixit_hint
*hint_1
= richloc
.get_fixit_hint (1);
4745 ASSERT_EQ (column_range (21, 20), get_affected_range (hint_1
, CU_BYTES
));
4746 ASSERT_EQ (column_range (21, 21), get_printed_columns (hint_1
));
4748 /* Verify that they're printed correctly. */
4749 test_diagnostic_context dc
;
4750 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4752 " int a5[][0][0] = { 1, 2 };\n"
4755 pp_formatted_text (dc
.printer
));
4758 /* Various overlapping insertions, some occurring "out of order"
4759 (reproducing the fix-it hints from PR c/81405). */
4761 test_diagnostic_context dc
;
4762 rich_location
richloc (line_table
, col_20
);
4764 richloc
.add_fixit_insert_before (col_20
, "{{");
4765 richloc
.add_fixit_insert_before (col_21
, "}}");
4766 richloc
.add_fixit_insert_before (col_23
, "{");
4767 richloc
.add_fixit_insert_before (col_21
, "}");
4768 richloc
.add_fixit_insert_before (col_23
, "{{");
4769 richloc
.add_fixit_insert_before (col_25
, "}");
4770 richloc
.add_fixit_insert_before (col_21
, "}");
4771 richloc
.add_fixit_insert_before (col_1
, "{");
4772 richloc
.add_fixit_insert_before (col_25
, "}");
4773 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4775 " int a5[][0][0] = { 1, 2 };\n"
4778 " {{1}}}}, {{{2 }}\n",
4779 pp_formatted_text (dc
.printer
));
4783 /* Insertion fix-it hint: adding a "break;" on a line by itself. */
4786 test_fixit_insert_containing_newline (const line_table_case
&case_
)
4788 /* Create a tempfile and write some text to it.
4789 .........................0000000001111111.
4790 .........................1234567890123456. */
4791 const char *old_content
= (" case 'a':\n" /* line 1. */
4792 " x = a;\n" /* line 2. */
4793 " case 'b':\n" /* line 3. */
4794 " x = b;\n");/* line 4. */
4796 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
4797 line_table_test
ltt (case_
);
4798 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 3);
4800 location_t case_start
= linemap_position_for_column (line_table
, 5);
4801 location_t case_finish
= linemap_position_for_column (line_table
, 13);
4802 location_t case_loc
= make_location (case_start
, case_start
, case_finish
);
4803 location_t line_start
= linemap_position_for_column (line_table
, 1);
4805 if (case_finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
4808 /* Add a "break;" on a line by itself before line 3 i.e. before
4809 column 1 of line 3. */
4811 rich_location
richloc (line_table
, case_loc
);
4812 richloc
.add_fixit_insert_before (line_start
, " break;\n");
4814 /* Without line numbers. */
4816 test_diagnostic_context dc
;
4817 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4823 pp_formatted_text (dc
.printer
));
4826 /* With line numbers. */
4828 test_diagnostic_context dc
;
4829 dc
.show_line_numbers_p
= true;
4830 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4836 pp_formatted_text (dc
.printer
));
4840 /* Verify that attempts to add text with a newline fail when the
4841 insertion point is *not* at the start of a line. */
4843 rich_location
richloc (line_table
, case_loc
);
4844 richloc
.add_fixit_insert_before (case_start
, "break;\n");
4845 ASSERT_TRUE (richloc
.seen_impossible_fixit_p ());
4846 test_diagnostic_context dc
;
4847 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4851 pp_formatted_text (dc
.printer
));
4855 /* Insertion fix-it hint: adding a "#include <stdio.h>\n" to the top
4856 of the file, where the fix-it is printed in a different line-span
4857 to the primary range of the diagnostic. */
4860 test_fixit_insert_containing_newline_2 (const line_table_case
&case_
)
4862 /* Create a tempfile and write some text to it.
4863 .........................0000000001111111.
4864 .........................1234567890123456. */
4865 const char *old_content
= ("test (int ch)\n" /* line 1. */
4867 " putchar (ch);\n" /* line 3. */
4868 "}\n"); /* line 4. */
4870 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
4871 line_table_test
ltt (case_
);
4873 const line_map_ordinary
*ord_map
= linemap_check_ordinary
4874 (linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 0));
4875 linemap_line_start (line_table
, 1, 100);
4877 /* The primary range is the "putchar" token. */
4878 location_t putchar_start
4879 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 2);
4880 location_t putchar_finish
4881 = linemap_position_for_line_and_column (line_table
, ord_map
, 3, 8);
4882 location_t putchar_loc
4883 = make_location (putchar_start
, putchar_start
, putchar_finish
);
4884 rich_location
richloc (line_table
, putchar_loc
);
4886 /* Add a "#include <stdio.h>" on a line by itself at the top of the file. */
4887 location_t file_start
4888 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 1);
4889 richloc
.add_fixit_insert_before (file_start
, "#include <stdio.h>\n");
4891 if (putchar_finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
4895 test_diagnostic_context dc
;
4896 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4899 "+#include <stdio.h>\n"
4904 pp_formatted_text (dc
.printer
));
4907 /* With line-numbering, the line spans are close enough to be
4908 consolidated, since it makes little sense to skip line 2. */
4910 test_diagnostic_context dc
;
4911 dc
.show_line_numbers_p
= true;
4912 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4914 " +++ |+#include <stdio.h>\n"
4915 " 1 | test (int ch)\n"
4917 " 3 | putchar (ch);\n"
4919 pp_formatted_text (dc
.printer
));
4923 /* Replacement fix-it hint containing a newline.
4924 This will fail, as newlines are only supported when inserting at the
4925 beginning of a line. */
4928 test_fixit_replace_containing_newline (const line_table_case
&case_
)
4930 /* Create a tempfile and write some text to it.
4931 .........................0000000001111.
4932 .........................1234567890123. */
4933 const char *old_content
= "foo = bar ();\n";
4935 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
4936 line_table_test
ltt (case_
);
4937 linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 1);
4939 /* Replace the " = " with "\n = ", as if we were reformatting an
4940 overly long line. */
4941 location_t start
= linemap_position_for_column (line_table
, 4);
4942 location_t finish
= linemap_position_for_column (line_table
, 6);
4943 location_t loc
= linemap_position_for_column (line_table
, 13);
4944 rich_location
richloc (line_table
, loc
);
4945 source_range range
= source_range::from_locations (start
, finish
);
4946 richloc
.add_fixit_replace (range
, "\n =");
4948 /* Arbitrary newlines are not yet supported within fix-it hints, so
4949 the fix-it should not be displayed. */
4950 ASSERT_TRUE (richloc
.seen_impossible_fixit_p ());
4952 if (finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
4955 test_diagnostic_context dc
;
4956 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
4960 pp_formatted_text (dc
.printer
));
4963 /* Fix-it hint, attempting to delete a newline.
4964 This will fail, as we currently only support fix-it hints that
4965 affect one line at a time. */
4968 test_fixit_deletion_affecting_newline (const line_table_case
&case_
)
4970 /* Create a tempfile and write some text to it.
4971 ..........................0000000001111.
4972 ..........................1234567890123. */
4973 const char *old_content
= ("foo = bar (\n"
4976 temp_source_file
tmp (SELFTEST_LOCATION
, ".c", old_content
);
4977 line_table_test
ltt (case_
);
4978 const line_map_ordinary
*ord_map
= linemap_check_ordinary
4979 (linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 0));
4980 linemap_line_start (line_table
, 1, 100);
4982 /* Attempt to delete the " (\n...)". */
4984 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 10);
4986 = linemap_position_for_line_and_column (line_table
, ord_map
, 1, 11);
4988 = linemap_position_for_line_and_column (line_table
, ord_map
, 2, 7);
4989 location_t loc
= make_location (caret
, start
, finish
);
4990 rich_location
richloc (line_table
, loc
);
4991 richloc
. add_fixit_remove ();
4993 /* Fix-it hints that affect more than one line are not yet supported, so
4994 the fix-it should not be displayed. */
4995 ASSERT_TRUE (richloc
.seen_impossible_fixit_p ());
4997 if (finish
> LINE_MAP_MAX_LOCATION_WITH_COLS
)
5000 test_diagnostic_context dc
;
5001 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
5007 pp_formatted_text (dc
.printer
));
5010 /* Verify that line numbers are correctly printed for the case of
5011 a multiline range in which the width of the line numbers changes
5012 (e.g. from "9" to "10"). */
5015 test_line_numbers_multiline_range ()
5017 /* Create a tempfile and write some text to it. */
5019 for (int i
= 0; i
< 20; i
++)
5020 /* .........0000000001111111.
5021 .............1234567890123456. */
5022 pp_printf (&pp
, "this is line %i\n", i
+ 1);
5023 temp_source_file
tmp (SELFTEST_LOCATION
, ".txt", pp_formatted_text (&pp
));
5024 line_table_test ltt
;
5026 const line_map_ordinary
*ord_map
= linemap_check_ordinary
5027 (linemap_add (line_table
, LC_ENTER
, false, tmp
.get_filename (), 0));
5028 linemap_line_start (line_table
, 1, 100);
5030 /* Create a multi-line location, starting at the "line" of line 9, with
5031 a caret on the "is" of line 10, finishing on the "this" line 11. */
5034 = linemap_position_for_line_and_column (line_table
, ord_map
, 9, 9);
5036 = linemap_position_for_line_and_column (line_table
, ord_map
, 10, 6);
5038 = linemap_position_for_line_and_column (line_table
, ord_map
, 11, 4);
5039 location_t loc
= make_location (caret
, start
, finish
);
5041 test_diagnostic_context dc
;
5042 dc
.show_line_numbers_p
= true;
5043 dc
.min_margin_width
= 0;
5044 gcc_rich_location
richloc (loc
);
5045 diagnostic_show_locus (&dc
, &richloc
, DK_ERROR
);
5047 " 9 | this is line 9\n"
5049 "10 | this is line 10\n"
5050 " | ~~~~~^~~~~~~~~~\n"
5051 "11 | this is line 11\n"
5053 pp_formatted_text (dc
.printer
));
5056 /* Run all of the selftests within this file. */
5059 diagnostic_show_locus_c_tests ()
5063 test_layout_range_for_single_point ();
5064 test_layout_range_for_single_line ();
5065 test_layout_range_for_multiple_lines ();
5067 for_each_line_table_case (test_layout_x_offset_display_utf8
);
5069 test_get_line_bytes_without_trailing_whitespace ();
5071 test_diagnostic_show_locus_unknown_location ();
5073 for_each_line_table_case (test_diagnostic_show_locus_one_liner
);
5074 for_each_line_table_case (test_diagnostic_show_locus_one_liner_utf8
);
5075 for_each_line_table_case (test_add_location_if_nearby
);
5076 for_each_line_table_case (test_diagnostic_show_locus_fixit_lines
);
5077 for_each_line_table_case (test_fixit_consolidation
);
5078 for_each_line_table_case (test_overlapped_fixit_printing
);
5079 for_each_line_table_case (test_overlapped_fixit_printing_utf8
);
5080 for_each_line_table_case (test_overlapped_fixit_printing_2
);
5081 for_each_line_table_case (test_fixit_insert_containing_newline
);
5082 for_each_line_table_case (test_fixit_insert_containing_newline_2
);
5083 for_each_line_table_case (test_fixit_replace_containing_newline
);
5084 for_each_line_table_case (test_fixit_deletion_affecting_newline
);
5086 test_line_numbers_multiline_range ();
5089 } // namespace selftest
5091 #endif /* #if CHECKING_P */
5094 # pragma GCC diagnostic pop