2015-11-18 Alan Modra <amodra@gmail.com>
[official-gcc.git] / gcc / diagnostic-show-locus.c
blob22203cdbaa380d88aef3f8f2b38ea265d6f08d13
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
10 version.
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.
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/>. */
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"
31 #ifdef HAVE_TERMIOS_H
32 # include <termios.h>
33 #endif
35 #ifdef GWINSZ_IN_SYS_IOCTL
36 # include <sys/ioctl.h>
37 #endif
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. */
44 namespace {
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. */
50 struct point_state
52 int range_idx;
53 bool draw_caret_p;
56 /* A class to inject colorization codes when printing the diagnostic locus.
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
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. */
72 class colorizer
74 public:
75 colorizer (diagnostic_context *context,
76 const diagnostic_info *diagnostic);
77 ~colorizer ();
79 void set_range (int range_idx) { set_state (range_idx); }
80 void set_normal_text () { set_state (STATE_NORMAL_TEXT); }
82 private:
83 void set_state (int state);
84 void begin_state (int state);
85 void finish_state (int state);
87 private:
88 static const int STATE_NORMAL_TEXT = -1;
90 diagnostic_context *m_context;
91 const diagnostic_info *m_diagnostic;
92 int m_current_state;
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. */
103 class layout_point
105 public:
106 layout_point (const expanded_location &exploc)
107 : m_line (exploc.line),
108 m_column (exploc.column) {}
110 int m_line;
111 int m_column;
114 /* A class for use by "class layout" below: a filtered location_range. */
116 class layout_range
118 public:
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;
125 bool m_show_caret_p;
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. */
133 struct line_bounds
135 int m_first_non_ws;
136 int m_last_non_ws;
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. */
147 class layout
149 public:
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);
159 private:
160 bool
161 get_state_at_point (/* Inputs. */
162 int row, int column,
163 int first_non_ws, int last_non_ws,
164 /* Outputs. */
165 point_state *out_state);
168 get_x_bound_for_row (int row, int caret_column,
169 int last_non_ws);
171 private:
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;
179 int m_first_line;
180 int m_last_line;
181 int m_x_offset;
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) :
191 m_context (context),
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
202 turn it off. */
204 colorizer::~colorizer ()
206 finish_state (m_current_state);
209 /* Update state, printing color codes if necessary if there's a state
210 change. */
212 void
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. */
225 void
226 colorizer::begin_state (int state)
228 switch (state)
230 case STATE_NORMAL_TEXT:
231 break;
233 case 0:
234 /* Make range 0 be the same color as the "kind" text
235 (error vs warning vs note). */
236 pp_string
237 (m_context->printer,
238 colorize_start (pp_show_color (m_context->printer),
239 diagnostic_get_color_for_kind (m_diagnostic->kind)));
240 break;
242 case 1:
243 pp_string (m_context->printer, m_range1_cs);
244 break;
246 case 2:
247 pp_string (m_context->printer, m_range2_cs);
248 break;
250 default:
251 /* We don't expect more than 3 ranges per diagnostic. */
252 gcc_unreachable ();
253 break;
257 /* Turn off any colorization for STATE. */
259 void
260 colorizer::finish_state (int state)
262 switch (state)
264 case STATE_NORMAL_TEXT:
265 break;
267 case 0:
268 pp_string (m_context->printer, m_caret_ce);
269 break;
271 default:
272 /* Within a range. */
273 gcc_assert (state > 0);
274 pp_string (m_context->printer, m_range_ce);
275 break;
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 --+-----------------------------------------------
324 Legend:
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
329 within it).
330 - 'a' indicates a subsequent point *after* the range. */
332 bool
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). */
343 return false;
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. */
352 return false;
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) */
358 return true;
359 else
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
375 in example B). */
376 return false;
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);
383 return true;
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. */
394 static int
395 get_line_width_without_trailing_whitespace (const char *line, int line_width)
397 int result = line_width;
398 while (result > 0)
400 char ch = line[result - 1];
401 if (ch == ' ' || ch == '\t')
402 result--;
403 else
404 break;
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'));
411 return result;
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),
435 m_x_offset (0)
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)
447 continue;
448 if (loc_range->m_finish.file != m_exploc.file)
449 continue;
450 if (loc_range->m_show_caret_p)
451 if (loc_range->m_caret.file != m_exploc.file)
452 continue;
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;
470 int line_width;
471 const char *line = location_get_source_line (m_exploc.file, m_exploc.line,
472 &line_width);
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
486 ranges.
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
489 untouched. */
491 bool
492 layout::print_source_line (int row, line_bounds *lbounds_out)
494 int line_width;
495 const char *line = location_get_source_line (m_exploc.file, row,
496 &line_width);
497 if (!line)
498 return false;
500 line += m_x_offset;
502 m_colorizer.set_normal_text ();
504 /* We will stop printing the source line at any trailing
505 whitespace. */
506 line_width = get_line_width_without_trailing_whitespace (line,
507 line_width);
509 pp_space (m_pp);
510 int first_non_ws = INT_MAX;
511 int last_non_ws = 0;
512 int column;
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)
529 bool in_range_p;
530 point_state state;
531 in_range_p = get_state_at_point (row, column,
532 0, INT_MAX,
533 &state);
534 if (in_range_p)
535 m_colorizer.set_range (state.range_idx);
536 else
537 m_colorizer.set_normal_text ();
539 char c = *line == '\t' ? ' ' : *line;
540 if (c == '\0')
541 c = ' ';
542 if (c != ' ')
544 last_non_ws = column;
545 if (first_non_ws == INT_MAX)
546 first_non_ws = column;
548 pp_character (m_pp, c);
549 line++;
551 pp_newline (m_pp);
553 lbounds_out->m_first_non_ws = first_non_ws;
554 lbounds_out->m_last_non_ws = last_non_ws;
555 return true;
558 /* Print a line consisting of the caret/underlines for the given
559 source line. */
561 void
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);
567 pp_space (m_pp);
568 for (int column = 1 + m_x_offset; column < x_bound; column++)
570 bool in_range_p;
571 point_state state;
572 in_range_p = get_state_at_point (row, column,
573 lbounds.m_first_non_ws,
574 lbounds.m_last_non_ws,
575 &state);
576 if (in_range_p)
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]);
583 else
584 pp_character (m_pp, '~');
586 else
588 /* Not in a range. */
589 m_colorizer.set_normal_text ();
590 pp_character (m_pp, ' ');
593 pp_newline (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). */
601 bool
602 layout::get_state_at_point (/* Inputs. */
603 int row, int column,
604 int first_non_ws, int last_non_ws,
605 /* Outputs. */
606 point_state *out_state)
608 layout_range *range;
609 int i;
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)
627 return false;
629 /* We are within a range. */
630 return true;
634 return false;
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;
652 layout_range *range;
653 int i;
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;
675 return result;
678 } /* End of anonymous namespace. */
680 /* Print the physical source code corresponding to the location of
681 this diagnostic, with additional annotations. */
683 void
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)
690 return;
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 ();
703 row <= last_line;
704 row++)
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. */
709 line_bounds lbounds;
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);