1 /* Diagnostic subroutines for printing source-code
2 Copyright (C) 1999-2015 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"
35 #ifdef GWINSZ_IN_SYS_IOCTL
36 # include <sys/ioctl.h>
39 /* Classes for rendering source code and diagnostics, within an
41 The work is done by "class layout", which embeds and uses
42 "class colorizer" and "class layout_range" to get things done. */
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
56 /* A class to inject colorization codes when printing the diagnostic locus.
58 It has one kind of colorization for each of:
60 - range 0 (the "primary location")
64 The class caches the lookup of the color codes for the above.
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. */
75 colorizer (diagnostic_context
*context
,
76 const diagnostic_info
*diagnostic
);
79 void set_range (int range_idx
) { set_state (range_idx
); }
80 void set_normal_text () { set_state (STATE_NORMAL_TEXT
); }
83 void set_state (int state
);
84 void begin_state (int state
);
85 void finish_state (int state
);
88 static const int STATE_NORMAL_TEXT
= -1;
90 diagnostic_context
*m_context
;
91 const diagnostic_info
*m_diagnostic
;
93 const char *m_caret_cs
;
94 const char *m_caret_ce
;
95 const char *m_range1_cs
;
96 const char *m_range2_cs
;
97 const char *m_range_ce
;
100 /* A point within a layout_range; similar to an expanded_location,
101 but after filtering on file. */
106 layout_point (const expanded_location
&exploc
)
107 : m_line (exploc
.line
),
108 m_column (exploc
.column
) {}
114 /* A class for use by "class layout" below: a filtered location_range. */
119 layout_range (const location_range
*loc_range
);
121 bool contains_point (int row
, int column
) const;
123 layout_point m_start
;
124 layout_point m_finish
;
126 layout_point m_caret
;
129 /* A struct for use by layout::print_source_line for telling
130 layout::print_annotation_line the extents of the source line that
131 it printed, so that underlines can be clipped appropriately. */
139 /* A class to control the overall layout when printing a diagnostic.
141 The layout is determined within the constructor.
142 It is then printed by repeatedly calling the "print_source_line"
143 and "print_annotation_line" methods.
145 We assume we have disjoint ranges. */
150 layout (diagnostic_context
*context
,
151 const diagnostic_info
*diagnostic
);
153 int get_first_line () const { return m_first_line
; }
154 int get_last_line () const { return m_last_line
; }
156 bool print_source_line (int row
, line_bounds
*lbounds_out
);
157 void print_annotation_line (int row
, const line_bounds lbounds
);
161 get_state_at_point (/* Inputs. */
163 int first_non_ws
, int last_non_ws
,
165 point_state
*out_state
);
168 get_x_bound_for_row (int row
, int caret_column
,
172 diagnostic_context
*m_context
;
173 pretty_printer
*m_pp
;
174 diagnostic_t m_diagnostic_kind
;
175 expanded_location m_exploc
;
176 colorizer m_colorizer
;
177 bool m_colorize_source_p
;
178 auto_vec
<layout_range
> m_layout_ranges
;
184 /* Implementation of "class colorizer". */
186 /* The constructor for "colorizer". Lookup and store color codes for the
187 different kinds of things we might need to print. */
189 colorizer::colorizer (diagnostic_context
*context
,
190 const diagnostic_info
*diagnostic
) :
192 m_diagnostic (diagnostic
),
193 m_current_state (STATE_NORMAL_TEXT
)
195 m_caret_ce
= colorize_stop (pp_show_color (context
->printer
));
196 m_range1_cs
= colorize_start (pp_show_color (context
->printer
), "range1");
197 m_range2_cs
= colorize_start (pp_show_color (context
->printer
), "range2");
198 m_range_ce
= colorize_stop (pp_show_color (context
->printer
));
201 /* The destructor for "colorize". If colorization is on, print a code to
204 colorizer::~colorizer ()
206 finish_state (m_current_state
);
209 /* Update state, printing color codes if necessary if there's a state
213 colorizer::set_state (int new_state
)
215 if (m_current_state
!= new_state
)
217 finish_state (m_current_state
);
218 m_current_state
= new_state
;
219 begin_state (new_state
);
223 /* Turn on any colorization for STATE. */
226 colorizer::begin_state (int state
)
230 case STATE_NORMAL_TEXT
:
234 /* Make range 0 be the same color as the "kind" text
235 (error vs warning vs note). */
238 colorize_start (pp_show_color (m_context
->printer
),
239 diagnostic_get_color_for_kind (m_diagnostic
->kind
)));
243 pp_string (m_context
->printer
, m_range1_cs
);
247 pp_string (m_context
->printer
, m_range2_cs
);
251 /* We don't expect more than 3 ranges per diagnostic. */
257 /* Turn off any colorization for STATE. */
260 colorizer::finish_state (int state
)
264 case STATE_NORMAL_TEXT
:
268 pp_string (m_context
->printer
, m_caret_ce
);
272 /* Within a range. */
273 gcc_assert (state
> 0);
274 pp_string (m_context
->printer
, m_range_ce
);
279 /* Implementation of class layout_range. */
281 /* The constructor for class layout_range.
282 Initialize various layout_point fields from expanded_location
283 equivalents; we've already filtered on file. */
285 layout_range::layout_range (const location_range
*loc_range
)
286 : m_start (loc_range
->m_start
),
287 m_finish (loc_range
->m_finish
),
288 m_show_caret_p (loc_range
->m_show_caret_p
),
289 m_caret (loc_range
->m_caret
)
293 /* Is (column, row) within the given range?
294 We've already filtered on the file.
296 Ranges are closed (both limits are within the range).
298 Example A: a single-line range:
299 start: (col=22, line=2)
300 finish: (col=38, line=2)
302 |00000011111111112222222222333333333344444444444
303 |34567890123456789012345678901234567890123456789
304 --+-----------------------------------------------
305 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
306 02|bbbbbbbbbbbbbbbbbbbSwwwwwwwwwwwwwwwFaaaaaaaaaaa
307 03|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
309 Example B: a multiline range with
310 start: (col=14, line=3)
311 finish: (col=08, line=5)
313 |00000011111111112222222222333333333344444444444
314 |34567890123456789012345678901234567890123456789
315 --+-----------------------------------------------
316 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
317 02|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
318 03|bbbbbbbbbbbSwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
319 04|wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
320 05|wwwwwFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
321 06|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
322 --+-----------------------------------------------
325 - 'b' indicates a point *before* the range
326 - 'S' indicates the start of the range
327 - 'w' indicates a point within the range
328 - 'F' indicates the finish of the range (which is
330 - 'a' indicates a subsequent point *after* the range. */
333 layout_range::contains_point (int row
, int column
) const
335 gcc_assert (m_start
.m_line
<= m_finish
.m_line
);
336 /* ...but the equivalent isn't true for the columns;
337 consider example B in the comment above. */
339 if (row
< m_start
.m_line
)
340 /* Points before the first line of the range are
341 outside it (corresponding to line 01 in example A
342 and lines 01 and 02 in example B above). */
345 if (row
== m_start
.m_line
)
346 /* On same line as start of range (corresponding
347 to line 02 in example A and line 03 in example B). */
349 if (column
< m_start
.m_column
)
350 /* Points on the starting line of the range, but
351 before the column in which it begins. */
354 if (row
< m_finish
.m_line
)
355 /* This is a multiline range; the point
356 is within it (corresponds to line 03 in example B
357 from column 14 onwards) */
361 /* This is a single-line range. */
362 gcc_assert (row
== m_finish
.m_line
);
363 return column
<= m_finish
.m_column
;
367 /* The point is in a line beyond that containing the
368 start of the range: lines 03 onwards in example A,
369 and lines 04 onwards in example B. */
370 gcc_assert (row
> m_start
.m_line
);
372 if (row
> m_finish
.m_line
)
373 /* The point is beyond the final line of the range
374 (lines 03 onwards in example A, and lines 06 onwards
378 if (row
< m_finish
.m_line
)
380 /* The point is in a line that's fully within a multiline
381 range (e.g. line 04 in example B). */
382 gcc_assert (m_start
.m_line
< m_finish
.m_line
);
386 gcc_assert (row
== m_finish
.m_line
);
388 return column
<= m_finish
.m_column
;
391 /* Given a source line LINE of length LINE_WIDTH, determine the width
392 without any trailing whitespace. */
395 get_line_width_without_trailing_whitespace (const char *line
, int line_width
)
397 int result
= line_width
;
400 char ch
= line
[result
- 1];
401 if (ch
== ' ' || ch
== '\t')
406 gcc_assert (result
>= 0);
407 gcc_assert (result
<= line_width
);
408 gcc_assert (result
== 0 ||
409 (line
[result
- 1] != ' '
410 && line
[result
-1] != '\t'));
414 /* Implementation of class layout. */
416 /* Constructor for class layout.
418 Filter the ranges from the rich_location to those that we can
419 sanely print, populating m_layout_ranges.
420 Determine the range of lines that we will print.
421 Determine m_x_offset, to ensure that the primary caret
422 will fit within the max_width provided by the diagnostic_context. */
424 layout::layout (diagnostic_context
* context
,
425 const diagnostic_info
*diagnostic
)
426 : m_context (context
),
427 m_pp (context
->printer
),
428 m_diagnostic_kind (diagnostic
->kind
),
429 m_exploc (diagnostic
->richloc
->lazily_expand_location ()),
430 m_colorizer (context
, diagnostic
),
431 m_colorize_source_p (context
->colorize_source_p
),
432 m_layout_ranges (rich_location::MAX_RANGES
),
433 m_first_line (m_exploc
.line
),
434 m_last_line (m_exploc
.line
),
437 rich_location
*richloc
= diagnostic
->richloc
;
438 for (unsigned int idx
= 0; idx
< richloc
->get_num_locations (); idx
++)
440 /* This diagnostic printer can only cope with "sufficiently sane" ranges.
441 Ignore any ranges that are awkward to handle. */
442 location_range
*loc_range
= richloc
->get_range (idx
);
444 /* If any part of the range isn't in the same file as the primary
445 location of this diagnostic, ignore the range. */
446 if (loc_range
->m_start
.file
!= m_exploc
.file
)
448 if (loc_range
->m_finish
.file
!= m_exploc
.file
)
450 if (loc_range
->m_show_caret_p
)
451 if (loc_range
->m_caret
.file
!= m_exploc
.file
)
454 /* Passed all the tests; add the range to m_layout_ranges so that
455 it will be printed. */
456 layout_range
ri (loc_range
);
457 m_layout_ranges
.safe_push (ri
);
459 /* Update m_first_line/m_last_line if necessary. */
460 if (loc_range
->m_start
.line
< m_first_line
)
461 m_first_line
= loc_range
->m_start
.line
;
462 if (loc_range
->m_finish
.line
> m_last_line
)
463 m_last_line
= loc_range
->m_finish
.line
;
466 /* Adjust m_x_offset.
467 Center the primary caret to fit in max_width; all columns
468 will be adjusted accordingly. */
469 int max_width
= m_context
->caret_max_width
;
471 const char *line
= location_get_source_line (m_exploc
.file
, m_exploc
.line
,
473 if (line
&& m_exploc
.column
<= line_width
)
475 int right_margin
= CARET_LINE_MARGIN
;
476 int column
= m_exploc
.column
;
477 right_margin
= MIN (line_width
- column
, right_margin
);
478 right_margin
= max_width
- right_margin
;
479 if (line_width
>= max_width
&& column
> right_margin
)
480 m_x_offset
= column
- right_margin
;
481 gcc_assert (m_x_offset
>= 0);
485 /* Attempt to print line ROW of source code, potentially colorized at any
487 Return true if the line was printed, populating *LBOUNDS_OUT.
488 Return false if the source line could not be read, leaving *LBOUNDS_OUT
492 layout::print_source_line (int row
, line_bounds
*lbounds_out
)
495 const char *line
= location_get_source_line (m_exploc
.file
, row
,
502 m_colorizer
.set_normal_text ();
504 /* We will stop printing the source line at any trailing
506 line_width
= get_line_width_without_trailing_whitespace (line
,
510 int first_non_ws
= INT_MAX
;
513 for (column
= 1 + m_x_offset
; column
<= line_width
; column
++)
515 /* Assuming colorization is enabled for the caret and underline
516 characters, we may also colorize the associated characters
517 within the source line.
519 For frontends that generate range information, we color the
520 associated characters in the source line the same as the
521 carets and underlines in the annotation line, to make it easier
522 for the reader to see the pertinent code.
524 For frontends that only generate carets, we don't colorize the
525 characters above them, since this would look strange (e.g.
526 colorizing just the first character in a token). */
527 if (m_colorize_source_p
)
531 in_range_p
= get_state_at_point (row
, column
,
535 m_colorizer
.set_range (state
.range_idx
);
537 m_colorizer
.set_normal_text ();
539 char c
= *line
== '\t' ? ' ' : *line
;
544 last_non_ws
= column
;
545 if (first_non_ws
== INT_MAX
)
546 first_non_ws
= column
;
548 pp_character (m_pp
, c
);
553 lbounds_out
->m_first_non_ws
= first_non_ws
;
554 lbounds_out
->m_last_non_ws
= last_non_ws
;
558 /* Print a line consisting of the caret/underlines for the given
562 layout::print_annotation_line (int row
, const line_bounds lbounds
)
564 int x_bound
= get_x_bound_for_row (row
, m_exploc
.column
,
565 lbounds
.m_last_non_ws
);
568 for (int column
= 1 + m_x_offset
; column
< x_bound
; column
++)
572 in_range_p
= get_state_at_point (row
, column
,
573 lbounds
.m_first_non_ws
,
574 lbounds
.m_last_non_ws
,
578 /* Within a range. Draw either the caret or an underline. */
579 m_colorizer
.set_range (state
.range_idx
);
580 if (state
.draw_caret_p
)
581 /* Draw the caret. */
582 pp_character (m_pp
, m_context
->caret_chars
[state
.range_idx
]);
584 pp_character (m_pp
, '~');
588 /* Not in a range. */
589 m_colorizer
.set_normal_text ();
590 pp_character (m_pp
, ' ');
596 /* Return true if (ROW/COLUMN) is within a range of the layout.
597 If it returns true, OUT_STATE is written to, with the
598 range index, and whether we should draw the caret at
599 (ROW/COLUMN) (as opposed to an underline). */
602 layout::get_state_at_point (/* Inputs. */
604 int first_non_ws
, int last_non_ws
,
606 point_state
*out_state
)
610 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
612 if (range
->contains_point (row
, column
))
614 out_state
->range_idx
= i
;
616 /* Are we at the range's caret? is it visible? */
617 out_state
->draw_caret_p
= false;
618 if (row
== range
->m_caret
.m_line
619 && column
== range
->m_caret
.m_column
)
620 out_state
->draw_caret_p
= range
->m_show_caret_p
;
622 /* Within a multiline range, don't display any underline
623 in any leading or trailing whitespace on a line.
624 We do display carets, however. */
625 if (!out_state
->draw_caret_p
)
626 if (column
< first_non_ws
|| column
> last_non_ws
)
629 /* We are within a range. */
637 /* Helper function for use by layout::print_line when printing the
638 annotation line under the source line.
639 Get the column beyond the rightmost one that could contain a caret or
640 range marker, given that we stop rendering at trailing whitespace.
641 ROW is the source line within the given file.
642 CARET_COLUMN is the column of range 0's caret.
643 LAST_NON_WS_COLUMN is the last column containing a non-whitespace
644 character of source (as determined when printing the source line). */
647 layout::get_x_bound_for_row (int row
, int caret_column
,
648 int last_non_ws_column
)
650 int result
= caret_column
+ 1;
654 FOR_EACH_VEC_ELT (m_layout_ranges
, i
, range
)
656 if (row
>= range
->m_start
.m_line
)
658 if (range
->m_finish
.m_line
== row
)
660 /* On the final line within a range; ensure that
661 we render up to the end of the range. */
662 if (result
<= range
->m_finish
.m_column
)
663 result
= range
->m_finish
.m_column
+ 1;
665 else if (row
< range
->m_finish
.m_line
)
667 /* Within a multiline range; ensure that we render up to the
668 last non-whitespace column. */
669 if (result
<= last_non_ws_column
)
670 result
= last_non_ws_column
+ 1;
678 } /* End of anonymous namespace. */
680 /* Print the physical source code corresponding to the location of
681 this diagnostic, with additional annotations. */
684 diagnostic_show_locus (diagnostic_context
* context
,
685 const diagnostic_info
*diagnostic
)
687 if (!context
->show_caret
688 || diagnostic_location (diagnostic
, 0) <= BUILTINS_LOCATION
689 || diagnostic_location (diagnostic
, 0) == context
->last_location
)
692 context
->last_location
= diagnostic_location (diagnostic
, 0);
694 pp_newline (context
->printer
);
696 const char *saved_prefix
= pp_get_prefix (context
->printer
);
697 pp_set_prefix (context
->printer
, NULL
);
700 layout
layout (context
, diagnostic
);
701 int last_line
= layout
.get_last_line ();
702 for (int row
= layout
.get_first_line ();
706 /* Print the source line, followed by an annotation line
707 consisting of any caret/underlines. If the source line can't
708 be read, print nothing. */
710 if (layout
.print_source_line (row
, &lbounds
))
711 layout
.print_annotation_line (row
, lbounds
);
714 /* The closing scope here leads to the dtor for layout and thus
715 colorizer being called here, which affects the precise
716 place where colorization is turned off in the unittest
717 for colorized output. */
720 pp_set_prefix (context
->printer
, saved_prefix
);