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 
set_range(int range_idx)79   void set_range (int range_idx) { set_state (range_idx); }
set_normal_text()80   void set_normal_text () { set_state (STATE_NORMAL_TEXT); }
set_fixit_hint()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:
layout_point(const expanded_location & exploc)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 expanded_location *start_exploc,
121 		const expanded_location *finish_exploc,
122 		bool show_caret_p,
123 		const expanded_location *caret_exploc);
124 
125   bool contains_point (int row, int column) const;
126 
127   layout_point m_start;
128   layout_point m_finish;
129   bool m_show_caret_p;
130   layout_point m_caret;
131 };
132 
133 /* A struct for use by layout::print_source_line for telling
134    layout::print_annotation_line the extents of the source line that
135    it printed, so that underlines can be clipped appropriately.  */
136 
137 struct line_bounds
138 {
139   int m_first_non_ws;
140   int m_last_non_ws;
141 };
142 
143 /* A range of contiguous source lines within a layout (e.g. "lines 5-10"
144    or "line 23").  During the layout ctor, layout::calculate_line_spans
145    splits the pertinent source lines into a list of disjoint line_span
146    instances (e.g. lines 5-10, lines 15-20, line 23).  */
147 
148 struct line_span
149 {
line_spanline_span150   line_span (linenum_type first_line, linenum_type last_line)
151     : m_first_line (first_line), m_last_line (last_line)
152   {
153     gcc_assert (first_line <= last_line);
154   }
get_first_lineline_span155   linenum_type get_first_line () const { return m_first_line; }
get_last_lineline_span156   linenum_type get_last_line () const { return m_last_line; }
157 
contains_line_pline_span158   bool contains_line_p (linenum_type line) const
159   {
160     return line >= m_first_line && line <= m_last_line;
161   }
162 
comparatorline_span163   static int comparator (const void *p1, const void *p2)
164   {
165     const line_span *ls1 = (const line_span *)p1;
166     const line_span *ls2 = (const line_span *)p2;
167     int first_line_diff = (int)ls1->m_first_line - (int)ls2->m_first_line;
168     if (first_line_diff)
169       return first_line_diff;
170     return (int)ls1->m_last_line - (int)ls2->m_last_line;
171   }
172 
173   linenum_type m_first_line;
174   linenum_type m_last_line;
175 };
176 
177 /* A class to control the overall layout when printing a diagnostic.
178 
179    The layout is determined within the constructor.
180    It is then printed by repeatedly calling the "print_source_line",
181    "print_annotation_line" and "print_any_fixits" methods.
182 
183    We assume we have disjoint ranges.  */
184 
185 class layout
186 {
187  public:
188   layout (diagnostic_context *context,
189 	  const diagnostic_info *diagnostic);
190 
get_num_line_spans()191   int get_num_line_spans () const { return m_line_spans.length (); }
get_line_span(int idx)192   const line_span *get_line_span (int idx) const { return &m_line_spans[idx]; }
193 
194   bool print_heading_for_line_span_index_p (int line_span_idx) const;
195 
196   expanded_location get_expanded_location (const line_span *) const;
197 
198   bool print_source_line (int row, line_bounds *lbounds_out);
199   void print_annotation_line (int row, const line_bounds lbounds);
200   void print_any_fixits (int row, const rich_location *richloc);
201 
202  private:
203   void calculate_line_spans ();
204 
205   void print_newline ();
206 
207   bool
208   get_state_at_point (/* Inputs.  */
209 		      int row, int column,
210 		      int first_non_ws, int last_non_ws,
211 		      /* Outputs.  */
212 		      point_state *out_state);
213 
214   int
215   get_x_bound_for_row (int row, int caret_column,
216 		       int last_non_ws);
217 
218   void
219   move_to_column (int *column, int dest_column);
220 
221  private:
222   diagnostic_context *m_context;
223   pretty_printer *m_pp;
224   diagnostic_t m_diagnostic_kind;
225   expanded_location m_exploc;
226   colorizer m_colorizer;
227   bool m_colorize_source_p;
228   auto_vec <layout_range> m_layout_ranges;
229   auto_vec <line_span> m_line_spans;
230   int m_x_offset;
231 };
232 
233 /* Implementation of "class colorizer".  */
234 
235 /* The constructor for "colorizer".  Lookup and store color codes for the
236    different kinds of things we might need to print.  */
237 
colorizer(diagnostic_context * context,const diagnostic_info * diagnostic)238 colorizer::colorizer (diagnostic_context *context,
239 		      const diagnostic_info *diagnostic) :
240   m_context (context),
241   m_diagnostic (diagnostic),
242   m_current_state (STATE_NORMAL_TEXT)
243 {
244   m_caret_ce = colorize_stop (pp_show_color (context->printer));
245   m_range1_cs = colorize_start (pp_show_color (context->printer), "range1");
246   m_range2_cs = colorize_start (pp_show_color (context->printer), "range2");
247   m_range_ce = colorize_stop (pp_show_color (context->printer));
248 }
249 
250 /* The destructor for "colorize".  If colorization is on, print a code to
251    turn it off.  */
252 
~colorizer()253 colorizer::~colorizer ()
254 {
255   finish_state (m_current_state);
256 }
257 
258 /* Update state, printing color codes if necessary if there's a state
259    change.  */
260 
261 void
set_state(int new_state)262 colorizer::set_state (int new_state)
263 {
264   if (m_current_state != new_state)
265     {
266       finish_state (m_current_state);
267       m_current_state = new_state;
268       begin_state (new_state);
269     }
270 }
271 
272 /* Turn on any colorization for STATE.  */
273 
274 void
begin_state(int state)275 colorizer::begin_state (int state)
276 {
277   switch (state)
278     {
279     case STATE_NORMAL_TEXT:
280       break;
281 
282     case 0:
283       /* Make range 0 be the same color as the "kind" text
284 	 (error vs warning vs note).  */
285       pp_string
286 	(m_context->printer,
287 	 colorize_start (pp_show_color (m_context->printer),
288 			 diagnostic_get_color_for_kind (m_diagnostic->kind)));
289       break;
290 
291     case 1:
292       pp_string (m_context->printer, m_range1_cs);
293       break;
294 
295     case 2:
296       pp_string (m_context->printer, m_range2_cs);
297       break;
298 
299     default:
300       /* We don't expect more than 3 ranges per diagnostic.  */
301       gcc_unreachable ();
302       break;
303     }
304 }
305 
306 /* Turn off any colorization for STATE.  */
307 
308 void
finish_state(int state)309 colorizer::finish_state (int state)
310 {
311   switch (state)
312     {
313     case STATE_NORMAL_TEXT:
314       break;
315 
316     case 0:
317       pp_string (m_context->printer, m_caret_ce);
318       break;
319 
320     default:
321       /* Within a range.  */
322       gcc_assert (state > 0);
323       pp_string (m_context->printer, m_range_ce);
324       break;
325     }
326 }
327 
328 /* Implementation of class layout_range.  */
329 
330 /* The constructor for class layout_range.
331    Initialize various layout_point fields from expanded_location
332    equivalents; we've already filtered on file.  */
333 
layout_range(const expanded_location * start_exploc,const expanded_location * finish_exploc,bool show_caret_p,const expanded_location * caret_exploc)334 layout_range::layout_range (const expanded_location *start_exploc,
335 			    const expanded_location *finish_exploc,
336 			    bool show_caret_p,
337 			    const expanded_location *caret_exploc)
338 : m_start (*start_exploc),
339   m_finish (*finish_exploc),
340   m_show_caret_p (show_caret_p),
341   m_caret (*caret_exploc)
342 {
343 }
344 
345 /* Is (column, row) within the given range?
346    We've already filtered on the file.
347 
348    Ranges are closed (both limits are within the range).
349 
350    Example A: a single-line range:
351      start:  (col=22, line=2)
352      finish: (col=38, line=2)
353 
354   |00000011111111112222222222333333333344444444444
355   |34567890123456789012345678901234567890123456789
356 --+-----------------------------------------------
357 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
358 02|bbbbbbbbbbbbbbbbbbbSwwwwwwwwwwwwwwwFaaaaaaaaaaa
359 03|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
360 
361    Example B: a multiline range with
362      start:  (col=14, line=3)
363      finish: (col=08, line=5)
364 
365   |00000011111111112222222222333333333344444444444
366   |34567890123456789012345678901234567890123456789
367 --+-----------------------------------------------
368 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
369 02|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
370 03|bbbbbbbbbbbSwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
371 04|wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
372 05|wwwwwFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
373 06|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
374 --+-----------------------------------------------
375 
376    Legend:
377    - 'b' indicates a point *before* the range
378    - 'S' indicates the start of the range
379    - 'w' indicates a point within the range
380    - 'F' indicates the finish of the range (which is
381 	 within it).
382    - 'a' indicates a subsequent point *after* the range.  */
383 
384 bool
contains_point(int row,int column)385 layout_range::contains_point (int row, int column) const
386 {
387   gcc_assert (m_start.m_line <= m_finish.m_line);
388   /* ...but the equivalent isn't true for the columns;
389      consider example B in the comment above.  */
390 
391   if (row < m_start.m_line)
392     /* Points before the first line of the range are
393        outside it (corresponding to line 01 in example A
394        and lines 01 and 02 in example B above).  */
395     return false;
396 
397   if (row == m_start.m_line)
398     /* On same line as start of range (corresponding
399        to line 02 in example A and line 03 in example B).  */
400     {
401       if (column < m_start.m_column)
402 	/* Points on the starting line of the range, but
403 	   before the column in which it begins.  */
404 	return false;
405 
406       if (row < m_finish.m_line)
407 	/* This is a multiline range; the point
408 	   is within it (corresponds to line 03 in example B
409 	   from column 14 onwards) */
410 	return true;
411       else
412 	{
413 	  /* This is a single-line range.  */
414 	  gcc_assert (row == m_finish.m_line);
415 	  return column <= m_finish.m_column;
416 	}
417     }
418 
419   /* The point is in a line beyond that containing the
420      start of the range: lines 03 onwards in example A,
421      and lines 04 onwards in example B.  */
422   gcc_assert (row > m_start.m_line);
423 
424   if (row > m_finish.m_line)
425     /* The point is beyond the final line of the range
426        (lines 03 onwards in example A, and lines 06 onwards
427        in example B).  */
428     return false;
429 
430   if (row < m_finish.m_line)
431     {
432       /* The point is in a line that's fully within a multiline
433 	 range (e.g. line 04 in example B).  */
434       gcc_assert (m_start.m_line < m_finish.m_line);
435       return true;
436     }
437 
438   gcc_assert (row ==  m_finish.m_line);
439 
440   return column <= m_finish.m_column;
441 }
442 
443 /* Given a source line LINE of length LINE_WIDTH, determine the width
444    without any trailing whitespace.  */
445 
446 static int
get_line_width_without_trailing_whitespace(const char * line,int line_width)447 get_line_width_without_trailing_whitespace (const char *line, int line_width)
448 {
449   int result = line_width;
450   while (result > 0)
451     {
452       char ch = line[result - 1];
453       if (ch == ' ' || ch == '\t')
454 	result--;
455       else
456 	break;
457     }
458   gcc_assert (result >= 0);
459   gcc_assert (result <= line_width);
460   gcc_assert (result == 0 ||
461 	      (line[result - 1] != ' '
462 	       && line[result -1] != '\t'));
463   return result;
464 }
465 
466 /* Helper function for layout's ctor, for sanitizing locations relative
467    to the primary location within a diagnostic.
468 
469    Compare LOC_A and LOC_B to see if it makes sense to print underlines
470    connecting their expanded locations.  Doing so is only guaranteed to
471    make sense if the locations share the same macro expansion "history"
472    i.e. they can be traced through the same macro expansions, eventually
473    reaching an ordinary map.
474 
475    This may be too strong a condition, but it effectively sanitizes
476    PR c++/70105, which has an example of printing an expression where the
477    final location of the expression is in a different macro, which
478    erroneously was leading to hundreds of lines of irrelevant source
479    being printed.  */
480 
481 static bool
compatible_locations_p(location_t loc_a,location_t loc_b)482 compatible_locations_p (location_t loc_a, location_t loc_b)
483 {
484   if (IS_ADHOC_LOC (loc_a))
485     loc_a = get_location_from_adhoc_loc (line_table, loc_a);
486   if (IS_ADHOC_LOC (loc_b))
487     loc_b = get_location_from_adhoc_loc (line_table, loc_b);
488 
489   /* If either location is one of the special locations outside of a
490      linemap, they are only compatible if they are equal.  */
491   if (loc_a < RESERVED_LOCATION_COUNT
492       || loc_b < RESERVED_LOCATION_COUNT)
493     return loc_a == loc_b;
494 
495   const line_map *map_a = linemap_lookup (line_table, loc_a);
496   linemap_assert (map_a);
497 
498   const line_map *map_b = linemap_lookup (line_table, loc_b);
499   linemap_assert (map_b);
500 
501   /* Are they within the same map?  */
502   if (map_a == map_b)
503     {
504       /* Are both within the same macro expansion?  */
505       if (linemap_macro_expansion_map_p (map_a))
506 	{
507 	  /* Expand each location towards the spelling location, and
508 	     recurse.  */
509 	  const line_map_macro *macro_map = linemap_check_macro (map_a);
510 	  source_location loc_a_toward_spelling
511 	    = linemap_macro_map_loc_unwind_toward_spelling (line_table,
512 							    macro_map,
513 							    loc_a);
514 	  source_location loc_b_toward_spelling
515 	    = linemap_macro_map_loc_unwind_toward_spelling (line_table,
516 							    macro_map,
517 							    loc_b);
518 	  return compatible_locations_p (loc_a_toward_spelling,
519 					 loc_b_toward_spelling);
520 	}
521 
522       /* Otherwise they are within the same ordinary map.  */
523       return true;
524     }
525   else
526     {
527       /* Within different maps.  */
528 
529       /* If either is within a macro expansion, they are incompatible.  */
530       if (linemap_macro_expansion_map_p (map_a)
531 	  || linemap_macro_expansion_map_p (map_b))
532 	return false;
533 
534       /* Within two different ordinary maps; they are compatible iff they
535 	 are in the same file.  */
536       const line_map_ordinary *ord_map_a = linemap_check_ordinary (map_a);
537       const line_map_ordinary *ord_map_b = linemap_check_ordinary (map_b);
538       return ord_map_a->to_file == ord_map_b->to_file;
539     }
540 }
541 
542 /* Implementation of class layout.  */
543 
544 /* Constructor for class layout.
545 
546    Filter the ranges from the rich_location to those that we can
547    sanely print, populating m_layout_ranges.
548    Determine the range of lines that we will print, splitting them
549    up into an ordered list of disjoint spans of contiguous line numbers.
550    Determine m_x_offset, to ensure that the primary caret
551    will fit within the max_width provided by the diagnostic_context.  */
552 
layout(diagnostic_context * context,const diagnostic_info * diagnostic)553 layout::layout (diagnostic_context * context,
554 		const diagnostic_info *diagnostic)
555 : m_context (context),
556   m_pp (context->printer),
557   m_diagnostic_kind (diagnostic->kind),
558   m_exploc (diagnostic->richloc->get_expanded_location (0)),
559   m_colorizer (context, diagnostic),
560   m_colorize_source_p (context->colorize_source_p),
561   m_layout_ranges (rich_location::MAX_RANGES),
562   m_line_spans (1 + rich_location::MAX_RANGES),
563   m_x_offset (0)
564 {
565   rich_location *richloc = diagnostic->richloc;
566   source_location primary_loc = richloc->get_range (0)->m_loc;
567 
568   for (unsigned int idx = 0; idx < richloc->get_num_locations (); idx++)
569     {
570       /* This diagnostic printer can only cope with "sufficiently sane" ranges.
571 	 Ignore any ranges that are awkward to handle.  */
572       const location_range *loc_range = richloc->get_range (idx);
573 
574       /* Split the "range" into caret and range information.  */
575       source_range src_range = get_range_from_loc (line_table, loc_range->m_loc);
576 
577       /* Expand the various locations.  */
578       expanded_location start
579 	= linemap_client_expand_location_to_spelling_point (src_range.m_start);
580       expanded_location finish
581 	= linemap_client_expand_location_to_spelling_point (src_range.m_finish);
582       expanded_location caret
583 	= linemap_client_expand_location_to_spelling_point (loc_range->m_loc);
584 
585       /* If any part of the range isn't in the same file as the primary
586 	 location of this diagnostic, ignore the range.  */
587       if (start.file != m_exploc.file)
588 	continue;
589       if (finish.file != m_exploc.file)
590 	continue;
591       if (loc_range->m_show_caret_p)
592 	if (caret.file != m_exploc.file)
593 	  continue;
594 
595       /* Sanitize the caret location for non-primary ranges.  */
596       if (m_layout_ranges.length () > 0)
597 	if (loc_range->m_show_caret_p)
598 	  if (!compatible_locations_p (loc_range->m_loc, primary_loc))
599 	    /* Discard any non-primary ranges that can't be printed
600 	       sanely relative to the primary location.  */
601 	    continue;
602 
603       /* Everything is now known to be in the correct source file,
604 	 but it may require further sanitization.  */
605       layout_range ri (&start, &finish, loc_range->m_show_caret_p, &caret);
606 
607       /* If we have a range that finishes before it starts (perhaps
608 	 from something built via macro expansion), printing the
609 	 range is likely to be nonsensical.  Also, attempting to do so
610 	 breaks assumptions within the printing code  (PR c/68473).
611 	 Similarly, don't attempt to print ranges if one or both ends
612 	 of the range aren't sane to print relative to the
613 	 primary location (PR c++/70105).  */
614       if (start.line > finish.line
615 	  || !compatible_locations_p (src_range.m_start, primary_loc)
616 	  || !compatible_locations_p (src_range.m_finish, primary_loc))
617 	{
618 	  /* Is this the primary location?  */
619 	  if (m_layout_ranges.length () == 0)
620 	    {
621 	      /* We want to print the caret for the primary location, but
622 		 we must sanitize away m_start and m_finish.  */
623 	      ri.m_start = ri.m_caret;
624 	      ri.m_finish = ri.m_caret;
625 	    }
626 	  else
627 	    /* This is a non-primary range; ignore it.  */
628 	    continue;
629 	}
630 
631       /* Passed all the tests; add the range to m_layout_ranges so that
632 	 it will be printed.  */
633       m_layout_ranges.safe_push (ri);
634     }
635 
636   /* Populate m_line_spans.  */
637   calculate_line_spans ();
638 
639   /* Adjust m_x_offset.
640      Center the primary caret to fit in max_width; all columns
641      will be adjusted accordingly.  */
642   int max_width = m_context->caret_max_width;
643   int line_width;
644   const char *line = location_get_source_line (m_exploc.file, m_exploc.line,
645 					       &line_width);
646   if (line && m_exploc.column <= line_width)
647     {
648       int right_margin = CARET_LINE_MARGIN;
649       int column = m_exploc.column;
650       right_margin = MIN (line_width - column, right_margin);
651       right_margin = max_width - right_margin;
652       if (line_width >= max_width && column > right_margin)
653 	m_x_offset = column - right_margin;
654       gcc_assert (m_x_offset >= 0);
655     }
656 }
657 
658 /* Return true iff we should print a heading when starting the
659    line span with the given index.  */
660 
661 bool
print_heading_for_line_span_index_p(int line_span_idx)662 layout::print_heading_for_line_span_index_p (int line_span_idx) const
663 {
664   /* We print a heading for every change of line span, hence for every
665      line span after the initial one.  */
666   if (line_span_idx > 0)
667     return true;
668 
669   /* We also do it for the initial span if the primary location of the
670      diagnostic is in a different span.  */
671   if (m_exploc.line > (int)get_line_span (0)->m_last_line)
672     return true;
673 
674   return false;
675 }
676 
677 /* Get an expanded_location for the first location of interest within
678    the given line_span.
679    Used when printing a heading to indicate a new line span.  */
680 
681 expanded_location
get_expanded_location(const line_span * line_span)682 layout::get_expanded_location (const line_span *line_span) const
683 {
684   /* Whenever possible, use the caret location.  */
685   if (line_span->contains_line_p (m_exploc.line))
686     return m_exploc;
687 
688   /* Otherwise, use the start of the first range that's present
689      within the line_span.  */
690   for (unsigned int i = 0; i < m_layout_ranges.length (); i++)
691     {
692       const layout_range *lr = &m_layout_ranges[i];
693       if (line_span->contains_line_p (lr->m_start.m_line))
694 	{
695 	  expanded_location exploc = m_exploc;
696 	  exploc.line = lr->m_start.m_line;
697 	  exploc.column = lr->m_start.m_column;
698 	  return exploc;
699 	}
700     }
701 
702   /* It should not be possible to have a line span that didn't
703      contain any of the layout_range instances.  */
704   gcc_unreachable ();
705   return m_exploc;
706 }
707 
708 /* We want to print the pertinent source code at a diagnostic.  The
709    rich_location can contain multiple locations.  This will have been
710    filtered into m_exploc (the caret for the primary location) and
711    m_layout_ranges, for those ranges within the same source file.
712 
713    We will print a subset of the lines within the source file in question,
714    as a collection of "spans" of lines.
715 
716    This function populates m_line_spans with an ordered, disjoint list of
717    the line spans of interest.
718 
719    For example, if the primary caret location is on line 7, with ranges
720    covering lines 5-6 and lines 9-12:
721 
722      004
723      005                   |RANGE 0
724      006                   |RANGE 0
725      007  |PRIMARY CARET
726      008
727      009                                |RANGE 1
728      010                                |RANGE 1
729      011                                |RANGE 1
730      012                                |RANGE 1
731      013
732 
733    then we want two spans: lines 5-7 and lines 9-12.  */
734 
735 void
calculate_line_spans()736 layout::calculate_line_spans ()
737 {
738   /* This should only be called once, by the ctor.  */
739   gcc_assert (m_line_spans.length () == 0);
740 
741   /* Populate tmp_spans with individual spans, for each of
742      m_exploc, and for m_layout_ranges.  */
743   auto_vec<line_span> tmp_spans (1 + rich_location::MAX_RANGES);
744   tmp_spans.safe_push (line_span (m_exploc.line, m_exploc.line));
745   for (unsigned int i = 0; i < m_layout_ranges.length (); i++)
746     {
747       const layout_range *lr = &m_layout_ranges[i];
748       gcc_assert (lr->m_start.m_line <= lr->m_finish.m_line);
749       tmp_spans.safe_push (line_span (lr->m_start.m_line,
750 				      lr->m_finish.m_line));
751     }
752 
753   /* Sort them.  */
754   tmp_spans.qsort(line_span::comparator);
755 
756   /* Now iterate through tmp_spans, copying into m_line_spans, and
757      combining where possible.  */
758   gcc_assert (tmp_spans.length () > 0);
759   m_line_spans.safe_push (tmp_spans[0]);
760   for (unsigned int i = 1; i < tmp_spans.length (); i++)
761     {
762       line_span *current = &m_line_spans[m_line_spans.length () - 1];
763       const line_span *next = &tmp_spans[i];
764       gcc_assert (next->m_first_line >= current->m_first_line);
765       if (next->m_first_line <= current->m_last_line + 1)
766 	{
767 	  /* We can merge them. */
768 	  if (next->m_last_line > current->m_last_line)
769 	    current->m_last_line = next->m_last_line;
770 	}
771       else
772 	{
773 	  /* No merger possible.  */
774 	  m_line_spans.safe_push (*next);
775 	}
776     }
777 
778   /* Verify the result, in m_line_spans.  */
779   gcc_assert (m_line_spans.length () > 0);
780   for (unsigned int i = 1; i < m_line_spans.length (); i++)
781     {
782       const line_span *prev = &m_line_spans[i - 1];
783       const line_span *next = &m_line_spans[i];
784       /* The individual spans must be sane.  */
785       gcc_assert (prev->m_first_line <= prev->m_last_line);
786       gcc_assert (next->m_first_line <= next->m_last_line);
787       /* The spans must be ordered.  */
788       gcc_assert (prev->m_first_line < next->m_first_line);
789       /* There must be a gap of at least one line between separate spans.  */
790       gcc_assert ((prev->m_last_line + 1) < next->m_first_line);
791     }
792 }
793 
794 /* Attempt to print line ROW of source code, potentially colorized at any
795    ranges.
796    Return true if the line was printed, populating *LBOUNDS_OUT.
797    Return false if the source line could not be read, leaving *LBOUNDS_OUT
798    untouched.  */
799 
800 bool
print_source_line(int row,line_bounds * lbounds_out)801 layout::print_source_line (int row, line_bounds *lbounds_out)
802 {
803   int line_width;
804   const char *line = location_get_source_line (m_exploc.file, row,
805 					       &line_width);
806   if (!line)
807     return false;
808 
809   m_colorizer.set_normal_text ();
810 
811   /* We will stop printing the source line at any trailing
812      whitespace.  */
813   line_width = get_line_width_without_trailing_whitespace (line,
814 							   line_width);
815   line += m_x_offset;
816 
817   pp_space (m_pp);
818   int first_non_ws = INT_MAX;
819   int last_non_ws = 0;
820   int column;
821   for (column = 1 + m_x_offset; column <= line_width; column++)
822     {
823       /* Assuming colorization is enabled for the caret and underline
824 	 characters, we may also colorize the associated characters
825 	 within the source line.
826 
827 	 For frontends that generate range information, we color the
828 	 associated characters in the source line the same as the
829 	 carets and underlines in the annotation line, to make it easier
830 	 for the reader to see the pertinent code.
831 
832 	 For frontends that only generate carets, we don't colorize the
833 	 characters above them, since this would look strange (e.g.
834 	 colorizing just the first character in a token).  */
835       if (m_colorize_source_p)
836 	{
837 	  bool in_range_p;
838 	  point_state state;
839 	  in_range_p = get_state_at_point (row, column,
840 					   0, INT_MAX,
841 					   &state);
842 	  if (in_range_p)
843 	    m_colorizer.set_range (state.range_idx);
844 	  else
845 	    m_colorizer.set_normal_text ();
846 	}
847       char c = *line == '\t' ? ' ' : *line;
848       if (c == '\0')
849 	c = ' ';
850       if (c != ' ')
851 	{
852 	  last_non_ws = column;
853 	  if (first_non_ws == INT_MAX)
854 	    first_non_ws = column;
855 	}
856       pp_character (m_pp, c);
857       line++;
858     }
859   print_newline ();
860 
861   lbounds_out->m_first_non_ws = first_non_ws;
862   lbounds_out->m_last_non_ws = last_non_ws;
863   return true;
864 }
865 
866 /* Print a line consisting of the caret/underlines for the given
867    source line.  */
868 
869 void
print_annotation_line(int row,const line_bounds lbounds)870 layout::print_annotation_line (int row, const line_bounds lbounds)
871 {
872   int x_bound = get_x_bound_for_row (row, m_exploc.column,
873 				     lbounds.m_last_non_ws);
874 
875   pp_space (m_pp);
876   for (int column = 1 + m_x_offset; column < x_bound; column++)
877     {
878       bool in_range_p;
879       point_state state;
880       in_range_p = get_state_at_point (row, column,
881 				       lbounds.m_first_non_ws,
882 				       lbounds.m_last_non_ws,
883 				       &state);
884       if (in_range_p)
885 	{
886 	  /* Within a range.  Draw either the caret or an underline.  */
887 	  m_colorizer.set_range (state.range_idx);
888 	  if (state.draw_caret_p)
889 	    /* Draw the caret.  */
890 	    pp_character (m_pp, m_context->caret_chars[state.range_idx]);
891 	  else
892 	    pp_character (m_pp, '~');
893 	}
894       else
895 	{
896 	  /* Not in a range.  */
897 	  m_colorizer.set_normal_text ();
898 	  pp_character (m_pp, ' ');
899 	}
900     }
901   print_newline ();
902 }
903 
904 /* If there are any fixit hints on source line ROW within RICHLOC, print them.
905    They are printed in order, attempting to combine them onto lines, but
906    starting new lines if necessary.  */
907 
908 void
print_any_fixits(int row,const rich_location * richloc)909 layout::print_any_fixits (int row, const rich_location *richloc)
910 {
911   int column = 0;
912   for (unsigned int i = 0; i < richloc->get_num_fixit_hints (); i++)
913     {
914       fixit_hint *hint = richloc->get_fixit_hint (i);
915       if (hint->affects_line_p (m_exploc.file, row))
916 	{
917 	  /* For now we assume each fixit hint can only touch one line.  */
918 	  switch (hint->get_kind ())
919 	    {
920 	    case fixit_hint::INSERT:
921 	      {
922 		fixit_insert *insert = static_cast <fixit_insert *> (hint);
923 		/* This assumes the insertion just affects one line.  */
924 		int start_column
925 		  = LOCATION_COLUMN (insert->get_location ());
926 		move_to_column (&column, start_column);
927 		m_colorizer.set_fixit_hint ();
928 		pp_string (m_pp, insert->get_string ());
929 		m_colorizer.set_normal_text ();
930 		column += insert->get_length ();
931 	      }
932 	      break;
933 
934 	    case fixit_hint::REMOVE:
935 	      {
936 		fixit_remove *remove = static_cast <fixit_remove *> (hint);
937 		/* This assumes the removal just affects one line.  */
938 		source_range src_range = remove->get_range ();
939 		int start_column = LOCATION_COLUMN (src_range.m_start);
940 		int finish_column = LOCATION_COLUMN (src_range.m_finish);
941 		move_to_column (&column, start_column);
942 		for (int column = start_column; column <= finish_column; column++)
943 		  {
944 		    m_colorizer.set_fixit_hint ();
945 		    pp_character (m_pp, '-');
946 		    m_colorizer.set_normal_text ();
947 		  }
948 	      }
949 	      break;
950 
951 	    case fixit_hint::REPLACE:
952 	      {
953 		fixit_replace *replace = static_cast <fixit_replace *> (hint);
954 		int start_column
955 		  = LOCATION_COLUMN (replace->get_range ().m_start);
956 		move_to_column (&column, start_column);
957 		m_colorizer.set_fixit_hint ();
958 		pp_string (m_pp, replace->get_string ());
959 		m_colorizer.set_normal_text ();
960 		column += replace->get_length ();
961 	      }
962 	      break;
963 
964 	    default:
965 	      gcc_unreachable ();
966 	    }
967 	}
968     }
969 
970   /* Add a trailing newline, if necessary.  */
971   move_to_column (&column, 0);
972 }
973 
974 /* Disable any colorization and emit a newline.  */
975 
976 void
print_newline()977 layout::print_newline ()
978 {
979   m_colorizer.set_normal_text ();
980   pp_newline (m_pp);
981 }
982 
983 /* Return true if (ROW/COLUMN) is within a range of the layout.
984    If it returns true, OUT_STATE is written to, with the
985    range index, and whether we should draw the caret at
986    (ROW/COLUMN) (as opposed to an underline).  */
987 
988 bool
get_state_at_point(int row,int column,int first_non_ws,int last_non_ws,point_state * out_state)989 layout::get_state_at_point (/* Inputs.  */
990 			    int row, int column,
991 			    int first_non_ws, int last_non_ws,
992 			    /* Outputs.  */
993 			    point_state *out_state)
994 {
995   layout_range *range;
996   int i;
997   FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
998     {
999       if (range->contains_point (row, column))
1000 	{
1001 	  out_state->range_idx = i;
1002 
1003 	  /* Are we at the range's caret?  is it visible? */
1004 	  out_state->draw_caret_p = false;
1005 	  if (range->m_show_caret_p
1006 	      && row == range->m_caret.m_line
1007 	      && column == range->m_caret.m_column)
1008 	    out_state->draw_caret_p = true;
1009 
1010 	  /* Within a multiline range, don't display any underline
1011 	     in any leading or trailing whitespace on a line.
1012 	     We do display carets, however.  */
1013 	  if (!out_state->draw_caret_p)
1014 	    if (column < first_non_ws || column > last_non_ws)
1015 	      return false;
1016 
1017 	  /* We are within a range.  */
1018 	  return true;
1019 	}
1020     }
1021 
1022   return false;
1023 }
1024 
1025 /* Helper function for use by layout::print_line when printing the
1026    annotation line under the source line.
1027    Get the column beyond the rightmost one that could contain a caret or
1028    range marker, given that we stop rendering at trailing whitespace.
1029    ROW is the source line within the given file.
1030    CARET_COLUMN is the column of range 0's caret.
1031    LAST_NON_WS_COLUMN is the last column containing a non-whitespace
1032    character of source (as determined when printing the source line).  */
1033 
1034 int
get_x_bound_for_row(int row,int caret_column,int last_non_ws_column)1035 layout::get_x_bound_for_row (int row, int caret_column,
1036 			     int last_non_ws_column)
1037 {
1038   int result = caret_column + 1;
1039 
1040   layout_range *range;
1041   int i;
1042   FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
1043     {
1044       if (row >= range->m_start.m_line)
1045 	{
1046 	  if (range->m_finish.m_line == row)
1047 	    {
1048 	      /* On the final line within a range; ensure that
1049 		 we render up to the end of the range.  */
1050 	      if (result <= range->m_finish.m_column)
1051 		result = range->m_finish.m_column + 1;
1052 	    }
1053 	  else if (row < range->m_finish.m_line)
1054 	    {
1055 	      /* Within a multiline range; ensure that we render up to the
1056 		 last non-whitespace column.  */
1057 	      if (result <= last_non_ws_column)
1058 		result = last_non_ws_column + 1;
1059 	    }
1060 	}
1061     }
1062 
1063   return result;
1064 }
1065 
1066 /* Given *COLUMN as an x-coordinate, print spaces to position
1067    successive output at DEST_COLUMN, printing a newline if necessary,
1068    and updating *COLUMN.  */
1069 
1070 void
move_to_column(int * column,int dest_column)1071 layout::move_to_column (int *column, int dest_column)
1072 {
1073   /* Start a new line if we need to.  */
1074   if (*column > dest_column)
1075     {
1076       print_newline ();
1077       *column = 0;
1078     }
1079 
1080   while (*column < dest_column)
1081     {
1082       pp_space (m_pp);
1083       (*column)++;
1084     }
1085 }
1086 
1087 } /* End of anonymous namespace.  */
1088 
1089 /* Print the physical source code corresponding to the location of
1090    this diagnostic, with additional annotations.  */
1091 
1092 void
diagnostic_show_locus(diagnostic_context * context,const diagnostic_info * diagnostic)1093 diagnostic_show_locus (diagnostic_context * context,
1094 		       const diagnostic_info *diagnostic)
1095 {
1096   pp_newline (context->printer);
1097 
1098   if (!context->show_caret
1099       || diagnostic_location (diagnostic, 0) <= BUILTINS_LOCATION
1100       || diagnostic_location (diagnostic, 0) == context->last_location)
1101     return;
1102 
1103   context->last_location = diagnostic_location (diagnostic, 0);
1104 
1105   const char *saved_prefix = pp_get_prefix (context->printer);
1106   pp_set_prefix (context->printer, NULL);
1107 
1108   layout layout (context, diagnostic);
1109   for (int line_span_idx = 0; line_span_idx < layout.get_num_line_spans ();
1110        line_span_idx++)
1111     {
1112       const line_span *line_span = layout.get_line_span (line_span_idx);
1113       if (layout.print_heading_for_line_span_index_p (line_span_idx))
1114 	{
1115 	  expanded_location exploc = layout.get_expanded_location (line_span);
1116 	  context->start_span (context, exploc);
1117 	}
1118       int last_line = line_span->get_last_line ();
1119       for (int row = line_span->get_first_line (); row <= last_line; row++)
1120 	{
1121 	  /* Print the source line, followed by an annotation line
1122 	     consisting of any caret/underlines, then any fixits.
1123 	     If the source line can't be read, print nothing.  */
1124 	  line_bounds lbounds;
1125 	  if (layout.print_source_line (row, &lbounds))
1126 	    {
1127 	      layout.print_annotation_line (row, lbounds);
1128 	      layout.print_any_fixits (row, diagnostic->richloc);
1129 	    }
1130 	}
1131     }
1132 
1133   pp_set_prefix (context->printer, saved_prefix);
1134 }
1135