]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/diagnostic-show-locus.c
Move diagnostic_show_locus and friends out into a new source file
[thirdparty/gcc.git] / gcc / diagnostic-show-locus.c
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>
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 /* If LINE is longer than MAX_WIDTH, and COLUMN is not smaller than
40 MAX_WIDTH by some margin, then adjust the start of the line such
41 that the COLUMN is smaller than MAX_WIDTH minus the margin. The
42 margin is either CARET_LINE_MARGIN characters or the difference
43 between the column and the length of the line, whatever is smaller.
44 The length of LINE is given by LINE_WIDTH. */
45 static const char *
46 adjust_line (const char *line, int line_width,
47 int max_width, int *column_p)
48 {
49 int right_margin = CARET_LINE_MARGIN;
50 int column = *column_p;
51
52 gcc_checking_assert (line_width >= column);
53 right_margin = MIN (line_width - column, right_margin);
54 right_margin = max_width - right_margin;
55 if (line_width >= max_width && column > right_margin)
56 {
57 line += column - right_margin;
58 *column_p = right_margin;
59 }
60 return line;
61 }
62
63 /* Print the physical source line corresponding to the location of
64 this diagnostic, and a caret indicating the precise column. This
65 function only prints two caret characters if the two locations
66 given by DIAGNOSTIC are on the same line according to
67 diagnostic_same_line(). */
68 void
69 diagnostic_show_locus (diagnostic_context * context,
70 const diagnostic_info *diagnostic)
71 {
72 if (!context->show_caret
73 || diagnostic_location (diagnostic, 0) <= BUILTINS_LOCATION
74 || diagnostic_location (diagnostic, 0) == context->last_location)
75 return;
76
77 context->last_location = diagnostic_location (diagnostic, 0);
78 expanded_location s0 = diagnostic_expand_location (diagnostic, 0);
79 expanded_location s1 = { };
80 /* Zero-initialized. This is checked later by diagnostic_print_caret_line. */
81
82 if (diagnostic_location (diagnostic, 1) > BUILTINS_LOCATION)
83 s1 = diagnostic_expand_location (diagnostic, 1);
84
85 diagnostic_print_caret_line (context, s0, s1,
86 context->caret_chars[0],
87 context->caret_chars[1]);
88 }
89
90 /* Print (part) of the source line given by xloc1 with caret1 pointing
91 at the column. If xloc2.column != 0 and it fits within the same
92 line as xloc1 according to diagnostic_same_line (), then caret2 is
93 printed at xloc2.colum. Otherwise, the caller has to set up things
94 to print a second caret line for xloc2. */
95 void
96 diagnostic_print_caret_line (diagnostic_context * context,
97 expanded_location xloc1,
98 expanded_location xloc2,
99 char caret1, char caret2)
100 {
101 if (!diagnostic_same_line (context, xloc1, xloc2))
102 /* This will mean ignore xloc2. */
103 xloc2.column = 0;
104 else if (xloc1.column == xloc2.column)
105 xloc2.column++;
106
107 int cmax = MAX (xloc1.column, xloc2.column);
108 int line_width;
109 const char *line = location_get_source_line (xloc1.file, xloc1.line,
110 &line_width);
111 if (line == NULL || cmax > line_width)
112 return;
113
114 /* Center the interesting part of the source line to fit in
115 max_width, and adjust all columns accordingly. */
116 int max_width = context->caret_max_width;
117 int offset = (int) cmax;
118 line = adjust_line (line, line_width, max_width, &offset);
119 offset -= cmax;
120 cmax += offset;
121 xloc1.column += offset;
122 if (xloc2.column)
123 xloc2.column += offset;
124
125 /* Print the source line. */
126 pp_newline (context->printer);
127 const char *saved_prefix = pp_get_prefix (context->printer);
128 pp_set_prefix (context->printer, NULL);
129 pp_space (context->printer);
130 while (max_width > 0 && line_width > 0)
131 {
132 char c = *line == '\t' ? ' ' : *line;
133 if (c == '\0')
134 c = ' ';
135 pp_character (context->printer, c);
136 max_width--;
137 line_width--;
138 line++;
139 }
140 pp_newline (context->printer);
141
142 /* Print the caret under the line. */
143 const char *caret_cs, *caret_ce;
144 caret_cs = colorize_start (pp_show_color (context->printer), "caret");
145 caret_ce = colorize_stop (pp_show_color (context->printer));
146 int cmin = xloc2.column
147 ? MIN (xloc1.column, xloc2.column) : xloc1.column;
148 int caret_min = cmin == xloc1.column ? caret1 : caret2;
149 int caret_max = cmin == xloc1.column ? caret2 : caret1;
150
151 /* cmin is >= 1, but we indent with an extra space at the start like
152 we did above. */
153 int i;
154 for (i = 0; i < cmin; i++)
155 pp_space (context->printer);
156 pp_printf (context->printer, "%s%c%s", caret_cs, caret_min, caret_ce);
157
158 if (xloc2.column)
159 {
160 for (i++; i < cmax; i++)
161 pp_space (context->printer);
162 pp_printf (context->printer, "%s%c%s", caret_cs, caret_max, caret_ce);
163 }
164 pp_set_prefix (context->printer, saved_prefix);
165 pp_needs_newline (context->printer) = true;
166 }