]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/diagnostic-show-locus.c
Update copyright years.
[thirdparty/gcc.git] / gcc / diagnostic-show-locus.c
1 /* Diagnostic subroutines for printing source-code
2 Copyright (C) 1999-2016 Free Software Foundation, Inc.
3 Contributed by Gabriel Dos Reis <gdr@codesourcery.com>
4
5 This file is part of GCC.
6
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
10 version.
11
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
15 for more details.
16
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/>. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "version.h"
25 #include "demangle.h"
26 #include "intl.h"
27 #include "backtrace.h"
28 #include "diagnostic.h"
29 #include "diagnostic-color.h"
30
31 #ifdef HAVE_TERMIOS_H
32 # include <termios.h>
33 #endif
34
35 #ifdef GWINSZ_IN_SYS_IOCTL
36 # include <sys/ioctl.h>
37 #endif
38
39 /* Classes for rendering source code and diagnostics, within an
40 anonymous namespace.
41 The work is done by "class layout", which embeds and uses
42 "class colorizer" and "class layout_range" to get things done. */
43
44 namespace {
45
46 /* The state at a given point of the source code, assuming that we're
47 in a range: which range are we in, and whether we should draw a caret at
48 this point. */
49
50 struct point_state
51 {
52 int range_idx;
53 bool draw_caret_p;
54 };
55
56 /* A class to inject colorization codes when printing the diagnostic locus.
57
58 It has one kind of colorization for each of:
59 - normal text
60 - range 0 (the "primary location")
61 - range 1
62 - range 2
63
64 The class caches the lookup of the color codes for the above.
65
66 The class also has responsibility for tracking which of the above is
67 active, filtering out unnecessary changes. This allows
68 layout::print_source_line and layout::print_annotation_line
69 to simply request a colorization code for *every* character they print,
70 via this class, and have the filtering be done for them here. */
71
72 class colorizer
73 {
74 public:
75 colorizer (diagnostic_context *context,
76 const diagnostic_info *diagnostic);
77 ~colorizer ();
78
79 void set_range (int range_idx) { set_state (range_idx); }
80 void set_normal_text () { set_state (STATE_NORMAL_TEXT); }
81 void set_fixit_hint () { set_state (0); }
82
83 private:
84 void set_state (int state);
85 void begin_state (int state);
86 void finish_state (int state);
87
88 private:
89 static const int STATE_NORMAL_TEXT = -1;
90
91 diagnostic_context *m_context;
92 const diagnostic_info *m_diagnostic;
93 int m_current_state;
94 const char *m_caret_cs;
95 const char *m_caret_ce;
96 const char *m_range1_cs;
97 const char *m_range2_cs;
98 const char *m_range_ce;
99 };
100
101 /* A point within a layout_range; similar to an expanded_location,
102 but after filtering on file. */
103
104 class layout_point
105 {
106 public:
107 layout_point (const expanded_location &exploc)
108 : m_line (exploc.line),
109 m_column (exploc.column) {}
110
111 int m_line;
112 int m_column;
113 };
114
115 /* A class for use by "class layout" below: a filtered location_range. */
116
117 class layout_range
118 {
119 public:
120 layout_range (const location_range *loc_range);
121
122 bool contains_point (int row, int column) const;
123
124 layout_point m_start;
125 layout_point m_finish;
126 bool m_show_caret_p;
127 layout_point m_caret;
128 };
129
130 /* A struct for use by layout::print_source_line for telling
131 layout::print_annotation_line the extents of the source line that
132 it printed, so that underlines can be clipped appropriately. */
133
134 struct line_bounds
135 {
136 int m_first_non_ws;
137 int m_last_non_ws;
138 };
139
140 /* A class to control the overall layout when printing a diagnostic.
141
142 The layout is determined within the constructor.
143 It is then printed by repeatedly calling the "print_source_line",
144 "print_annotation_line" and "print_any_fixits" methods.
145
146 We assume we have disjoint ranges. */
147
148 class layout
149 {
150 public:
151 layout (diagnostic_context *context,
152 const diagnostic_info *diagnostic);
153
154 int get_first_line () const { return m_first_line; }
155 int get_last_line () const { return m_last_line; }
156
157 bool print_source_line (int row, line_bounds *lbounds_out);
158 void print_annotation_line (int row, const line_bounds lbounds);
159 void print_any_fixits (int row, const rich_location *richloc);
160
161 private:
162 bool
163 get_state_at_point (/* Inputs. */
164 int row, int column,
165 int first_non_ws, int last_non_ws,
166 /* Outputs. */
167 point_state *out_state);
168
169 int
170 get_x_bound_for_row (int row, int caret_column,
171 int last_non_ws);
172
173 void
174 move_to_column (int *column, int dest_column);
175
176 private:
177 diagnostic_context *m_context;
178 pretty_printer *m_pp;
179 diagnostic_t m_diagnostic_kind;
180 expanded_location m_exploc;
181 colorizer m_colorizer;
182 bool m_colorize_source_p;
183 auto_vec <layout_range> m_layout_ranges;
184 int m_first_line;
185 int m_last_line;
186 int m_x_offset;
187 };
188
189 /* Implementation of "class colorizer". */
190
191 /* The constructor for "colorizer". Lookup and store color codes for the
192 different kinds of things we might need to print. */
193
194 colorizer::colorizer (diagnostic_context *context,
195 const diagnostic_info *diagnostic) :
196 m_context (context),
197 m_diagnostic (diagnostic),
198 m_current_state (STATE_NORMAL_TEXT)
199 {
200 m_caret_ce = colorize_stop (pp_show_color (context->printer));
201 m_range1_cs = colorize_start (pp_show_color (context->printer), "range1");
202 m_range2_cs = colorize_start (pp_show_color (context->printer), "range2");
203 m_range_ce = colorize_stop (pp_show_color (context->printer));
204 }
205
206 /* The destructor for "colorize". If colorization is on, print a code to
207 turn it off. */
208
209 colorizer::~colorizer ()
210 {
211 finish_state (m_current_state);
212 }
213
214 /* Update state, printing color codes if necessary if there's a state
215 change. */
216
217 void
218 colorizer::set_state (int new_state)
219 {
220 if (m_current_state != new_state)
221 {
222 finish_state (m_current_state);
223 m_current_state = new_state;
224 begin_state (new_state);
225 }
226 }
227
228 /* Turn on any colorization for STATE. */
229
230 void
231 colorizer::begin_state (int state)
232 {
233 switch (state)
234 {
235 case STATE_NORMAL_TEXT:
236 break;
237
238 case 0:
239 /* Make range 0 be the same color as the "kind" text
240 (error vs warning vs note). */
241 pp_string
242 (m_context->printer,
243 colorize_start (pp_show_color (m_context->printer),
244 diagnostic_get_color_for_kind (m_diagnostic->kind)));
245 break;
246
247 case 1:
248 pp_string (m_context->printer, m_range1_cs);
249 break;
250
251 case 2:
252 pp_string (m_context->printer, m_range2_cs);
253 break;
254
255 default:
256 /* We don't expect more than 3 ranges per diagnostic. */
257 gcc_unreachable ();
258 break;
259 }
260 }
261
262 /* Turn off any colorization for STATE. */
263
264 void
265 colorizer::finish_state (int state)
266 {
267 switch (state)
268 {
269 case STATE_NORMAL_TEXT:
270 break;
271
272 case 0:
273 pp_string (m_context->printer, m_caret_ce);
274 break;
275
276 default:
277 /* Within a range. */
278 gcc_assert (state > 0);
279 pp_string (m_context->printer, m_range_ce);
280 break;
281 }
282 }
283
284 /* Implementation of class layout_range. */
285
286 /* The constructor for class layout_range.
287 Initialize various layout_point fields from expanded_location
288 equivalents; we've already filtered on file. */
289
290 layout_range::layout_range (const location_range *loc_range)
291 : m_start (loc_range->m_start),
292 m_finish (loc_range->m_finish),
293 m_show_caret_p (loc_range->m_show_caret_p),
294 m_caret (loc_range->m_caret)
295 {
296 }
297
298 /* Is (column, row) within the given range?
299 We've already filtered on the file.
300
301 Ranges are closed (both limits are within the range).
302
303 Example A: a single-line range:
304 start: (col=22, line=2)
305 finish: (col=38, line=2)
306
307 |00000011111111112222222222333333333344444444444
308 |34567890123456789012345678901234567890123456789
309 --+-----------------------------------------------
310 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
311 02|bbbbbbbbbbbbbbbbbbbSwwwwwwwwwwwwwwwFaaaaaaaaaaa
312 03|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
313
314 Example B: a multiline range with
315 start: (col=14, line=3)
316 finish: (col=08, line=5)
317
318 |00000011111111112222222222333333333344444444444
319 |34567890123456789012345678901234567890123456789
320 --+-----------------------------------------------
321 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
322 02|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
323 03|bbbbbbbbbbbSwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
324 04|wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
325 05|wwwwwFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
326 06|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
327 --+-----------------------------------------------
328
329 Legend:
330 - 'b' indicates a point *before* the range
331 - 'S' indicates the start of the range
332 - 'w' indicates a point within the range
333 - 'F' indicates the finish of the range (which is
334 within it).
335 - 'a' indicates a subsequent point *after* the range. */
336
337 bool
338 layout_range::contains_point (int row, int column) const
339 {
340 gcc_assert (m_start.m_line <= m_finish.m_line);
341 /* ...but the equivalent isn't true for the columns;
342 consider example B in the comment above. */
343
344 if (row < m_start.m_line)
345 /* Points before the first line of the range are
346 outside it (corresponding to line 01 in example A
347 and lines 01 and 02 in example B above). */
348 return false;
349
350 if (row == m_start.m_line)
351 /* On same line as start of range (corresponding
352 to line 02 in example A and line 03 in example B). */
353 {
354 if (column < m_start.m_column)
355 /* Points on the starting line of the range, but
356 before the column in which it begins. */
357 return false;
358
359 if (row < m_finish.m_line)
360 /* This is a multiline range; the point
361 is within it (corresponds to line 03 in example B
362 from column 14 onwards) */
363 return true;
364 else
365 {
366 /* This is a single-line range. */
367 gcc_assert (row == m_finish.m_line);
368 return column <= m_finish.m_column;
369 }
370 }
371
372 /* The point is in a line beyond that containing the
373 start of the range: lines 03 onwards in example A,
374 and lines 04 onwards in example B. */
375 gcc_assert (row > m_start.m_line);
376
377 if (row > m_finish.m_line)
378 /* The point is beyond the final line of the range
379 (lines 03 onwards in example A, and lines 06 onwards
380 in example B). */
381 return false;
382
383 if (row < m_finish.m_line)
384 {
385 /* The point is in a line that's fully within a multiline
386 range (e.g. line 04 in example B). */
387 gcc_assert (m_start.m_line < m_finish.m_line);
388 return true;
389 }
390
391 gcc_assert (row == m_finish.m_line);
392
393 return column <= m_finish.m_column;
394 }
395
396 /* Given a source line LINE of length LINE_WIDTH, determine the width
397 without any trailing whitespace. */
398
399 static int
400 get_line_width_without_trailing_whitespace (const char *line, int line_width)
401 {
402 int result = line_width;
403 while (result > 0)
404 {
405 char ch = line[result - 1];
406 if (ch == ' ' || ch == '\t')
407 result--;
408 else
409 break;
410 }
411 gcc_assert (result >= 0);
412 gcc_assert (result <= line_width);
413 gcc_assert (result == 0 ||
414 (line[result - 1] != ' '
415 && line[result -1] != '\t'));
416 return result;
417 }
418
419 /* Implementation of class layout. */
420
421 /* Constructor for class layout.
422
423 Filter the ranges from the rich_location to those that we can
424 sanely print, populating m_layout_ranges.
425 Determine the range of lines that we will print.
426 Determine m_x_offset, to ensure that the primary caret
427 will fit within the max_width provided by the diagnostic_context. */
428
429 layout::layout (diagnostic_context * context,
430 const diagnostic_info *diagnostic)
431 : m_context (context),
432 m_pp (context->printer),
433 m_diagnostic_kind (diagnostic->kind),
434 m_exploc (diagnostic->richloc->lazily_expand_location ()),
435 m_colorizer (context, diagnostic),
436 m_colorize_source_p (context->colorize_source_p),
437 m_layout_ranges (rich_location::MAX_RANGES),
438 m_first_line (m_exploc.line),
439 m_last_line (m_exploc.line),
440 m_x_offset (0)
441 {
442 rich_location *richloc = diagnostic->richloc;
443 for (unsigned int idx = 0; idx < richloc->get_num_locations (); idx++)
444 {
445 /* This diagnostic printer can only cope with "sufficiently sane" ranges.
446 Ignore any ranges that are awkward to handle. */
447 const location_range *loc_range = richloc->get_range (idx);
448
449 /* If any part of the range isn't in the same file as the primary
450 location of this diagnostic, ignore the range. */
451 if (loc_range->m_start.file != m_exploc.file)
452 continue;
453 if (loc_range->m_finish.file != m_exploc.file)
454 continue;
455 if (loc_range->m_show_caret_p)
456 if (loc_range->m_caret.file != m_exploc.file)
457 continue;
458
459 /* Everything is now known to be in the correct source file,
460 but it may require further sanitization. */
461 layout_range ri (loc_range);
462
463 /* If we have a range that finishes before it starts (perhaps
464 from something built via macro expansion), printing the
465 range is likely to be nonsensical. Also, attempting to do so
466 breaks assumptions within the printing code (PR c/68473). */
467 if (loc_range->m_start.line > loc_range->m_finish.line)
468 {
469 /* Is this the primary location? */
470 if (m_layout_ranges.length () == 0)
471 {
472 /* We want to print the caret for the primary location, but
473 we must sanitize away m_start and m_finish. */
474 ri.m_start = ri.m_caret;
475 ri.m_finish = ri.m_caret;
476 }
477 else
478 /* This is a non-primary range; ignore it. */
479 continue;
480 }
481
482 /* Passed all the tests; add the range to m_layout_ranges so that
483 it will be printed. */
484 m_layout_ranges.safe_push (ri);
485
486 /* Update m_first_line/m_last_line if necessary. */
487 if (ri.m_start.m_line < m_first_line)
488 m_first_line = ri.m_start.m_line;
489 if (ri.m_finish.m_line > m_last_line)
490 m_last_line = ri.m_finish.m_line;
491 }
492
493 /* Adjust m_x_offset.
494 Center the primary caret to fit in max_width; all columns
495 will be adjusted accordingly. */
496 int max_width = m_context->caret_max_width;
497 int line_width;
498 const char *line = location_get_source_line (m_exploc.file, m_exploc.line,
499 &line_width);
500 if (line && m_exploc.column <= line_width)
501 {
502 int right_margin = CARET_LINE_MARGIN;
503 int column = m_exploc.column;
504 right_margin = MIN (line_width - column, right_margin);
505 right_margin = max_width - right_margin;
506 if (line_width >= max_width && column > right_margin)
507 m_x_offset = column - right_margin;
508 gcc_assert (m_x_offset >= 0);
509 }
510 }
511
512 /* Attempt to print line ROW of source code, potentially colorized at any
513 ranges.
514 Return true if the line was printed, populating *LBOUNDS_OUT.
515 Return false if the source line could not be read, leaving *LBOUNDS_OUT
516 untouched. */
517
518 bool
519 layout::print_source_line (int row, line_bounds *lbounds_out)
520 {
521 int line_width;
522 const char *line = location_get_source_line (m_exploc.file, row,
523 &line_width);
524 if (!line)
525 return false;
526
527 line += m_x_offset;
528
529 m_colorizer.set_normal_text ();
530
531 /* We will stop printing the source line at any trailing
532 whitespace. */
533 line_width = get_line_width_without_trailing_whitespace (line,
534 line_width);
535
536 pp_space (m_pp);
537 int first_non_ws = INT_MAX;
538 int last_non_ws = 0;
539 int column;
540 for (column = 1 + m_x_offset; column <= line_width; column++)
541 {
542 /* Assuming colorization is enabled for the caret and underline
543 characters, we may also colorize the associated characters
544 within the source line.
545
546 For frontends that generate range information, we color the
547 associated characters in the source line the same as the
548 carets and underlines in the annotation line, to make it easier
549 for the reader to see the pertinent code.
550
551 For frontends that only generate carets, we don't colorize the
552 characters above them, since this would look strange (e.g.
553 colorizing just the first character in a token). */
554 if (m_colorize_source_p)
555 {
556 bool in_range_p;
557 point_state state;
558 in_range_p = get_state_at_point (row, column,
559 0, INT_MAX,
560 &state);
561 if (in_range_p)
562 m_colorizer.set_range (state.range_idx);
563 else
564 m_colorizer.set_normal_text ();
565 }
566 char c = *line == '\t' ? ' ' : *line;
567 if (c == '\0')
568 c = ' ';
569 if (c != ' ')
570 {
571 last_non_ws = column;
572 if (first_non_ws == INT_MAX)
573 first_non_ws = column;
574 }
575 pp_character (m_pp, c);
576 line++;
577 }
578 pp_newline (m_pp);
579
580 lbounds_out->m_first_non_ws = first_non_ws;
581 lbounds_out->m_last_non_ws = last_non_ws;
582 return true;
583 }
584
585 /* Print a line consisting of the caret/underlines for the given
586 source line. */
587
588 void
589 layout::print_annotation_line (int row, const line_bounds lbounds)
590 {
591 int x_bound = get_x_bound_for_row (row, m_exploc.column,
592 lbounds.m_last_non_ws);
593
594 pp_space (m_pp);
595 for (int column = 1 + m_x_offset; column < x_bound; column++)
596 {
597 bool in_range_p;
598 point_state state;
599 in_range_p = get_state_at_point (row, column,
600 lbounds.m_first_non_ws,
601 lbounds.m_last_non_ws,
602 &state);
603 if (in_range_p)
604 {
605 /* Within a range. Draw either the caret or an underline. */
606 m_colorizer.set_range (state.range_idx);
607 if (state.draw_caret_p)
608 /* Draw the caret. */
609 pp_character (m_pp, m_context->caret_chars[state.range_idx]);
610 else
611 pp_character (m_pp, '~');
612 }
613 else
614 {
615 /* Not in a range. */
616 m_colorizer.set_normal_text ();
617 pp_character (m_pp, ' ');
618 }
619 }
620 pp_newline (m_pp);
621 }
622
623 /* If there are any fixit hints on source line ROW within RICHLOC, print them.
624 They are printed in order, attempting to combine them onto lines, but
625 starting new lines if necessary. */
626
627 void
628 layout::print_any_fixits (int row, const rich_location *richloc)
629 {
630 int column = 0;
631 for (unsigned int i = 0; i < richloc->get_num_fixit_hints (); i++)
632 {
633 fixit_hint *hint = richloc->get_fixit_hint (i);
634 if (hint->affects_line_p (m_exploc.file, row))
635 {
636 /* For now we assume each fixit hint can only touch one line. */
637 switch (hint->get_kind ())
638 {
639 case fixit_hint::INSERT:
640 {
641 fixit_insert *insert = static_cast <fixit_insert *> (hint);
642 /* This assumes the insertion just affects one line. */
643 int start_column
644 = LOCATION_COLUMN (insert->get_location ());
645 move_to_column (&column, start_column);
646 m_colorizer.set_fixit_hint ();
647 pp_string (m_pp, insert->get_string ());
648 m_colorizer.set_normal_text ();
649 column += insert->get_length ();
650 }
651 break;
652
653 case fixit_hint::REMOVE:
654 {
655 fixit_remove *remove = static_cast <fixit_remove *> (hint);
656 /* This assumes the removal just affects one line. */
657 source_range src_range = remove->get_range ();
658 int start_column = LOCATION_COLUMN (src_range.m_start);
659 int finish_column = LOCATION_COLUMN (src_range.m_finish);
660 move_to_column (&column, start_column);
661 for (int column = start_column; column <= finish_column; column++)
662 {
663 m_colorizer.set_fixit_hint ();
664 pp_character (m_pp, '-');
665 m_colorizer.set_normal_text ();
666 }
667 }
668 break;
669
670 case fixit_hint::REPLACE:
671 {
672 fixit_replace *replace = static_cast <fixit_replace *> (hint);
673 int start_column
674 = LOCATION_COLUMN (replace->get_range ().m_start);
675 move_to_column (&column, start_column);
676 m_colorizer.set_fixit_hint ();
677 pp_string (m_pp, replace->get_string ());
678 m_colorizer.set_normal_text ();
679 column += replace->get_length ();
680 }
681 break;
682
683 default:
684 gcc_unreachable ();
685 }
686 }
687 }
688 }
689
690 /* Return true if (ROW/COLUMN) is within a range of the layout.
691 If it returns true, OUT_STATE is written to, with the
692 range index, and whether we should draw the caret at
693 (ROW/COLUMN) (as opposed to an underline). */
694
695 bool
696 layout::get_state_at_point (/* Inputs. */
697 int row, int column,
698 int first_non_ws, int last_non_ws,
699 /* Outputs. */
700 point_state *out_state)
701 {
702 layout_range *range;
703 int i;
704 FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
705 {
706 if (range->contains_point (row, column))
707 {
708 out_state->range_idx = i;
709
710 /* Are we at the range's caret? is it visible? */
711 out_state->draw_caret_p = false;
712 if (row == range->m_caret.m_line
713 && column == range->m_caret.m_column)
714 out_state->draw_caret_p = range->m_show_caret_p;
715
716 /* Within a multiline range, don't display any underline
717 in any leading or trailing whitespace on a line.
718 We do display carets, however. */
719 if (!out_state->draw_caret_p)
720 if (column < first_non_ws || column > last_non_ws)
721 return false;
722
723 /* We are within a range. */
724 return true;
725 }
726 }
727
728 return false;
729 }
730
731 /* Helper function for use by layout::print_line when printing the
732 annotation line under the source line.
733 Get the column beyond the rightmost one that could contain a caret or
734 range marker, given that we stop rendering at trailing whitespace.
735 ROW is the source line within the given file.
736 CARET_COLUMN is the column of range 0's caret.
737 LAST_NON_WS_COLUMN is the last column containing a non-whitespace
738 character of source (as determined when printing the source line). */
739
740 int
741 layout::get_x_bound_for_row (int row, int caret_column,
742 int last_non_ws_column)
743 {
744 int result = caret_column + 1;
745
746 layout_range *range;
747 int i;
748 FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
749 {
750 if (row >= range->m_start.m_line)
751 {
752 if (range->m_finish.m_line == row)
753 {
754 /* On the final line within a range; ensure that
755 we render up to the end of the range. */
756 if (result <= range->m_finish.m_column)
757 result = range->m_finish.m_column + 1;
758 }
759 else if (row < range->m_finish.m_line)
760 {
761 /* Within a multiline range; ensure that we render up to the
762 last non-whitespace column. */
763 if (result <= last_non_ws_column)
764 result = last_non_ws_column + 1;
765 }
766 }
767 }
768
769 return result;
770 }
771
772 /* Given *COLUMN as an x-coordinate, print spaces to position
773 successive output at DEST_COLUMN, printing a newline if necessary,
774 and updating *COLUMN. */
775
776 void
777 layout::move_to_column (int *column, int dest_column)
778 {
779 /* Start a new line if we need to. */
780 if (*column > dest_column)
781 {
782 pp_newline (m_pp);
783 *column = 0;
784 }
785
786 while (*column < dest_column)
787 {
788 pp_space (m_pp);
789 (*column)++;
790 }
791 }
792
793 } /* End of anonymous namespace. */
794
795 /* Print the physical source code corresponding to the location of
796 this diagnostic, with additional annotations. */
797
798 void
799 diagnostic_show_locus (diagnostic_context * context,
800 const diagnostic_info *diagnostic)
801 {
802 if (!context->show_caret
803 || diagnostic_location (diagnostic, 0) <= BUILTINS_LOCATION
804 || diagnostic_location (diagnostic, 0) == context->last_location)
805 return;
806
807 context->last_location = diagnostic_location (diagnostic, 0);
808
809 pp_newline (context->printer);
810
811 const char *saved_prefix = pp_get_prefix (context->printer);
812 pp_set_prefix (context->printer, NULL);
813
814 {
815 layout layout (context, diagnostic);
816 int last_line = layout.get_last_line ();
817 for (int row = layout.get_first_line ();
818 row <= last_line;
819 row++)
820 {
821 /* Print the source line, followed by an annotation line
822 consisting of any caret/underlines, then any fixits.
823 If the source line can't be read, print nothing. */
824 line_bounds lbounds;
825 if (layout.print_source_line (row, &lbounds))
826 {
827 layout.print_annotation_line (row, lbounds);
828 layout.print_any_fixits (row, diagnostic->richloc);
829 }
830 }
831
832 /* The closing scope here leads to the dtor for layout and thus
833 colorizer being called here, which affects the precise
834 place where colorization is turned off in the unittest
835 for colorized output. */
836 }
837
838 pp_set_prefix (context->printer, saved_prefix);
839 }