annotate gcc/diagnostic-show-locus.c @ 16:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
16
kono
parents:
diff changeset
1 /* Diagnostic subroutines for printing source-code
kono
parents:
diff changeset
2 Copyright (C) 1999-2017 Free Software Foundation, Inc.
kono
parents:
diff changeset
3 Contributed by Gabriel Dos Reis <gdr@codesourcery.com>
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 This file is part of GCC.
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 GCC is free software; you can redistribute it and/or modify it under
kono
parents:
diff changeset
8 the terms of the GNU General Public License as published by the Free
kono
parents:
diff changeset
9 Software Foundation; either version 3, or (at your option) any later
kono
parents:
diff changeset
10 version.
kono
parents:
diff changeset
11
kono
parents:
diff changeset
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
kono
parents:
diff changeset
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
kono
parents:
diff changeset
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
kono
parents:
diff changeset
15 for more details.
kono
parents:
diff changeset
16
kono
parents:
diff changeset
17 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
18 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
19 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
20
kono
parents:
diff changeset
21 #include "config.h"
kono
parents:
diff changeset
22 #include "system.h"
kono
parents:
diff changeset
23 #include "coretypes.h"
kono
parents:
diff changeset
24 #include "version.h"
kono
parents:
diff changeset
25 #include "demangle.h"
kono
parents:
diff changeset
26 #include "intl.h"
kono
parents:
diff changeset
27 #include "backtrace.h"
kono
parents:
diff changeset
28 #include "diagnostic.h"
kono
parents:
diff changeset
29 #include "diagnostic-color.h"
kono
parents:
diff changeset
30 #include "gcc-rich-location.h"
kono
parents:
diff changeset
31 #include "selftest.h"
kono
parents:
diff changeset
32
kono
parents:
diff changeset
33 #ifdef HAVE_TERMIOS_H
kono
parents:
diff changeset
34 # include <termios.h>
kono
parents:
diff changeset
35 #endif
kono
parents:
diff changeset
36
kono
parents:
diff changeset
37 #ifdef GWINSZ_IN_SYS_IOCTL
kono
parents:
diff changeset
38 # include <sys/ioctl.h>
kono
parents:
diff changeset
39 #endif
kono
parents:
diff changeset
40
kono
parents:
diff changeset
41 /* Classes for rendering source code and diagnostics, within an
kono
parents:
diff changeset
42 anonymous namespace.
kono
parents:
diff changeset
43 The work is done by "class layout", which embeds and uses
kono
parents:
diff changeset
44 "class colorizer" and "class layout_range" to get things done. */
kono
parents:
diff changeset
45
kono
parents:
diff changeset
46 namespace {
kono
parents:
diff changeset
47
kono
parents:
diff changeset
48 /* The state at a given point of the source code, assuming that we're
kono
parents:
diff changeset
49 in a range: which range are we in, and whether we should draw a caret at
kono
parents:
diff changeset
50 this point. */
kono
parents:
diff changeset
51
kono
parents:
diff changeset
52 struct point_state
kono
parents:
diff changeset
53 {
kono
parents:
diff changeset
54 int range_idx;
kono
parents:
diff changeset
55 bool draw_caret_p;
kono
parents:
diff changeset
56 };
kono
parents:
diff changeset
57
kono
parents:
diff changeset
58 /* A class to inject colorization codes when printing the diagnostic locus.
kono
parents:
diff changeset
59
kono
parents:
diff changeset
60 It has one kind of colorization for each of:
kono
parents:
diff changeset
61 - normal text
kono
parents:
diff changeset
62 - range 0 (the "primary location")
kono
parents:
diff changeset
63 - range 1
kono
parents:
diff changeset
64 - range 2
kono
parents:
diff changeset
65
kono
parents:
diff changeset
66 The class caches the lookup of the color codes for the above.
kono
parents:
diff changeset
67
kono
parents:
diff changeset
68 The class also has responsibility for tracking which of the above is
kono
parents:
diff changeset
69 active, filtering out unnecessary changes. This allows
kono
parents:
diff changeset
70 layout::print_source_line and layout::print_annotation_line
kono
parents:
diff changeset
71 to simply request a colorization code for *every* character they print,
kono
parents:
diff changeset
72 via this class, and have the filtering be done for them here. */
kono
parents:
diff changeset
73
kono
parents:
diff changeset
74 class colorizer
kono
parents:
diff changeset
75 {
kono
parents:
diff changeset
76 public:
kono
parents:
diff changeset
77 colorizer (diagnostic_context *context,
kono
parents:
diff changeset
78 diagnostic_t diagnostic_kind);
kono
parents:
diff changeset
79 ~colorizer ();
kono
parents:
diff changeset
80
kono
parents:
diff changeset
81 void set_range (int range_idx) { set_state (range_idx); }
kono
parents:
diff changeset
82 void set_normal_text () { set_state (STATE_NORMAL_TEXT); }
kono
parents:
diff changeset
83 void set_fixit_insert () { set_state (STATE_FIXIT_INSERT); }
kono
parents:
diff changeset
84 void set_fixit_delete () { set_state (STATE_FIXIT_DELETE); }
kono
parents:
diff changeset
85
kono
parents:
diff changeset
86 private:
kono
parents:
diff changeset
87 void set_state (int state);
kono
parents:
diff changeset
88 void begin_state (int state);
kono
parents:
diff changeset
89 void finish_state (int state);
kono
parents:
diff changeset
90 const char *get_color_by_name (const char *);
kono
parents:
diff changeset
91
kono
parents:
diff changeset
92 private:
kono
parents:
diff changeset
93 static const int STATE_NORMAL_TEXT = -1;
kono
parents:
diff changeset
94 static const int STATE_FIXIT_INSERT = -2;
kono
parents:
diff changeset
95 static const int STATE_FIXIT_DELETE = -3;
kono
parents:
diff changeset
96
kono
parents:
diff changeset
97 diagnostic_context *m_context;
kono
parents:
diff changeset
98 diagnostic_t m_diagnostic_kind;
kono
parents:
diff changeset
99 int m_current_state;
kono
parents:
diff changeset
100 const char *m_range1;
kono
parents:
diff changeset
101 const char *m_range2;
kono
parents:
diff changeset
102 const char *m_fixit_insert;
kono
parents:
diff changeset
103 const char *m_fixit_delete;
kono
parents:
diff changeset
104 const char *m_stop_color;
kono
parents:
diff changeset
105 };
kono
parents:
diff changeset
106
kono
parents:
diff changeset
107 /* A point within a layout_range; similar to an expanded_location,
kono
parents:
diff changeset
108 but after filtering on file. */
kono
parents:
diff changeset
109
kono
parents:
diff changeset
110 class layout_point
kono
parents:
diff changeset
111 {
kono
parents:
diff changeset
112 public:
kono
parents:
diff changeset
113 layout_point (const expanded_location &exploc)
kono
parents:
diff changeset
114 : m_line (exploc.line),
kono
parents:
diff changeset
115 m_column (exploc.column) {}
kono
parents:
diff changeset
116
kono
parents:
diff changeset
117 int m_line;
kono
parents:
diff changeset
118 int m_column;
kono
parents:
diff changeset
119 };
kono
parents:
diff changeset
120
kono
parents:
diff changeset
121 /* A class for use by "class layout" below: a filtered location_range. */
kono
parents:
diff changeset
122
kono
parents:
diff changeset
123 class layout_range
kono
parents:
diff changeset
124 {
kono
parents:
diff changeset
125 public:
kono
parents:
diff changeset
126 layout_range (const expanded_location *start_exploc,
kono
parents:
diff changeset
127 const expanded_location *finish_exploc,
kono
parents:
diff changeset
128 bool show_caret_p,
kono
parents:
diff changeset
129 const expanded_location *caret_exploc);
kono
parents:
diff changeset
130
kono
parents:
diff changeset
131 bool contains_point (int row, int column) const;
kono
parents:
diff changeset
132 bool intersects_line_p (int row) const;
kono
parents:
diff changeset
133
kono
parents:
diff changeset
134 layout_point m_start;
kono
parents:
diff changeset
135 layout_point m_finish;
kono
parents:
diff changeset
136 bool m_show_caret_p;
kono
parents:
diff changeset
137 layout_point m_caret;
kono
parents:
diff changeset
138 };
kono
parents:
diff changeset
139
kono
parents:
diff changeset
140 /* A struct for use by layout::print_source_line for telling
kono
parents:
diff changeset
141 layout::print_annotation_line the extents of the source line that
kono
parents:
diff changeset
142 it printed, so that underlines can be clipped appropriately. */
kono
parents:
diff changeset
143
kono
parents:
diff changeset
144 struct line_bounds
kono
parents:
diff changeset
145 {
kono
parents:
diff changeset
146 int m_first_non_ws;
kono
parents:
diff changeset
147 int m_last_non_ws;
kono
parents:
diff changeset
148 };
kono
parents:
diff changeset
149
kono
parents:
diff changeset
150 /* A range of contiguous source lines within a layout (e.g. "lines 5-10"
kono
parents:
diff changeset
151 or "line 23"). During the layout ctor, layout::calculate_line_spans
kono
parents:
diff changeset
152 splits the pertinent source lines into a list of disjoint line_span
kono
parents:
diff changeset
153 instances (e.g. lines 5-10, lines 15-20, line 23). */
kono
parents:
diff changeset
154
kono
parents:
diff changeset
155 struct line_span
kono
parents:
diff changeset
156 {
kono
parents:
diff changeset
157 line_span (linenum_type first_line, linenum_type last_line)
kono
parents:
diff changeset
158 : m_first_line (first_line), m_last_line (last_line)
kono
parents:
diff changeset
159 {
kono
parents:
diff changeset
160 gcc_assert (first_line <= last_line);
kono
parents:
diff changeset
161 }
kono
parents:
diff changeset
162 linenum_type get_first_line () const { return m_first_line; }
kono
parents:
diff changeset
163 linenum_type get_last_line () const { return m_last_line; }
kono
parents:
diff changeset
164
kono
parents:
diff changeset
165 bool contains_line_p (linenum_type line) const
kono
parents:
diff changeset
166 {
kono
parents:
diff changeset
167 return line >= m_first_line && line <= m_last_line;
kono
parents:
diff changeset
168 }
kono
parents:
diff changeset
169
kono
parents:
diff changeset
170 static int comparator (const void *p1, const void *p2)
kono
parents:
diff changeset
171 {
kono
parents:
diff changeset
172 const line_span *ls1 = (const line_span *)p1;
kono
parents:
diff changeset
173 const line_span *ls2 = (const line_span *)p2;
kono
parents:
diff changeset
174 int first_line_diff = (int)ls1->m_first_line - (int)ls2->m_first_line;
kono
parents:
diff changeset
175 if (first_line_diff)
kono
parents:
diff changeset
176 return first_line_diff;
kono
parents:
diff changeset
177 return (int)ls1->m_last_line - (int)ls2->m_last_line;
kono
parents:
diff changeset
178 }
kono
parents:
diff changeset
179
kono
parents:
diff changeset
180 linenum_type m_first_line;
kono
parents:
diff changeset
181 linenum_type m_last_line;
kono
parents:
diff changeset
182 };
kono
parents:
diff changeset
183
kono
parents:
diff changeset
184 /* A class to control the overall layout when printing a diagnostic.
kono
parents:
diff changeset
185
kono
parents:
diff changeset
186 The layout is determined within the constructor.
kono
parents:
diff changeset
187 It is then printed by repeatedly calling the "print_source_line",
kono
parents:
diff changeset
188 "print_annotation_line" and "print_any_fixits" methods.
kono
parents:
diff changeset
189
kono
parents:
diff changeset
190 We assume we have disjoint ranges. */
kono
parents:
diff changeset
191
kono
parents:
diff changeset
192 class layout
kono
parents:
diff changeset
193 {
kono
parents:
diff changeset
194 public:
kono
parents:
diff changeset
195 layout (diagnostic_context *context,
kono
parents:
diff changeset
196 rich_location *richloc,
kono
parents:
diff changeset
197 diagnostic_t diagnostic_kind);
kono
parents:
diff changeset
198
kono
parents:
diff changeset
199 bool maybe_add_location_range (const location_range *loc_range,
kono
parents:
diff changeset
200 bool restrict_to_current_line_spans);
kono
parents:
diff changeset
201
kono
parents:
diff changeset
202 int get_num_line_spans () const { return m_line_spans.length (); }
kono
parents:
diff changeset
203 const line_span *get_line_span (int idx) const { return &m_line_spans[idx]; }
kono
parents:
diff changeset
204
kono
parents:
diff changeset
205 bool print_heading_for_line_span_index_p (int line_span_idx) const;
kono
parents:
diff changeset
206
kono
parents:
diff changeset
207 expanded_location get_expanded_location (const line_span *) const;
kono
parents:
diff changeset
208
kono
parents:
diff changeset
209 void print_line (int row);
kono
parents:
diff changeset
210
kono
parents:
diff changeset
211 private:
kono
parents:
diff changeset
212 bool will_show_line_p (int row) const;
kono
parents:
diff changeset
213 void print_leading_fixits (int row);
kono
parents:
diff changeset
214 void print_source_line (int row, const char *line, int line_width,
kono
parents:
diff changeset
215 line_bounds *lbounds_out);
kono
parents:
diff changeset
216 bool should_print_annotation_line_p (int row) const;
kono
parents:
diff changeset
217 void print_annotation_line (int row, const line_bounds lbounds);
kono
parents:
diff changeset
218 void print_trailing_fixits (int row);
kono
parents:
diff changeset
219
kono
parents:
diff changeset
220 bool annotation_line_showed_range_p (int line, int start_column,
kono
parents:
diff changeset
221 int finish_column) const;
kono
parents:
diff changeset
222 void show_ruler (int max_column) const;
kono
parents:
diff changeset
223
kono
parents:
diff changeset
224 bool validate_fixit_hint_p (const fixit_hint *hint);
kono
parents:
diff changeset
225
kono
parents:
diff changeset
226 void calculate_line_spans ();
kono
parents:
diff changeset
227
kono
parents:
diff changeset
228 void print_newline ();
kono
parents:
diff changeset
229
kono
parents:
diff changeset
230 bool
kono
parents:
diff changeset
231 get_state_at_point (/* Inputs. */
kono
parents:
diff changeset
232 int row, int column,
kono
parents:
diff changeset
233 int first_non_ws, int last_non_ws,
kono
parents:
diff changeset
234 /* Outputs. */
kono
parents:
diff changeset
235 point_state *out_state);
kono
parents:
diff changeset
236
kono
parents:
diff changeset
237 int
kono
parents:
diff changeset
238 get_x_bound_for_row (int row, int caret_column,
kono
parents:
diff changeset
239 int last_non_ws);
kono
parents:
diff changeset
240
kono
parents:
diff changeset
241 void
kono
parents:
diff changeset
242 move_to_column (int *column, int dest_column);
kono
parents:
diff changeset
243
kono
parents:
diff changeset
244 private:
kono
parents:
diff changeset
245 diagnostic_context *m_context;
kono
parents:
diff changeset
246 pretty_printer *m_pp;
kono
parents:
diff changeset
247 diagnostic_t m_diagnostic_kind;
kono
parents:
diff changeset
248 location_t m_primary_loc;
kono
parents:
diff changeset
249 expanded_location m_exploc;
kono
parents:
diff changeset
250 colorizer m_colorizer;
kono
parents:
diff changeset
251 bool m_colorize_source_p;
kono
parents:
diff changeset
252 auto_vec <layout_range> m_layout_ranges;
kono
parents:
diff changeset
253 auto_vec <const fixit_hint *> m_fixit_hints;
kono
parents:
diff changeset
254 auto_vec <line_span> m_line_spans;
kono
parents:
diff changeset
255 int m_x_offset;
kono
parents:
diff changeset
256 };
kono
parents:
diff changeset
257
kono
parents:
diff changeset
258 /* Implementation of "class colorizer". */
kono
parents:
diff changeset
259
kono
parents:
diff changeset
260 /* The constructor for "colorizer". Lookup and store color codes for the
kono
parents:
diff changeset
261 different kinds of things we might need to print. */
kono
parents:
diff changeset
262
kono
parents:
diff changeset
263 colorizer::colorizer (diagnostic_context *context,
kono
parents:
diff changeset
264 diagnostic_t diagnostic_kind) :
kono
parents:
diff changeset
265 m_context (context),
kono
parents:
diff changeset
266 m_diagnostic_kind (diagnostic_kind),
kono
parents:
diff changeset
267 m_current_state (STATE_NORMAL_TEXT)
kono
parents:
diff changeset
268 {
kono
parents:
diff changeset
269 m_range1 = get_color_by_name ("range1");
kono
parents:
diff changeset
270 m_range2 = get_color_by_name ("range2");
kono
parents:
diff changeset
271 m_fixit_insert = get_color_by_name ("fixit-insert");
kono
parents:
diff changeset
272 m_fixit_delete = get_color_by_name ("fixit-delete");
kono
parents:
diff changeset
273 m_stop_color = colorize_stop (pp_show_color (context->printer));
kono
parents:
diff changeset
274 }
kono
parents:
diff changeset
275
kono
parents:
diff changeset
276 /* The destructor for "colorize". If colorization is on, print a code to
kono
parents:
diff changeset
277 turn it off. */
kono
parents:
diff changeset
278
kono
parents:
diff changeset
279 colorizer::~colorizer ()
kono
parents:
diff changeset
280 {
kono
parents:
diff changeset
281 finish_state (m_current_state);
kono
parents:
diff changeset
282 }
kono
parents:
diff changeset
283
kono
parents:
diff changeset
284 /* Update state, printing color codes if necessary if there's a state
kono
parents:
diff changeset
285 change. */
kono
parents:
diff changeset
286
kono
parents:
diff changeset
287 void
kono
parents:
diff changeset
288 colorizer::set_state (int new_state)
kono
parents:
diff changeset
289 {
kono
parents:
diff changeset
290 if (m_current_state != new_state)
kono
parents:
diff changeset
291 {
kono
parents:
diff changeset
292 finish_state (m_current_state);
kono
parents:
diff changeset
293 m_current_state = new_state;
kono
parents:
diff changeset
294 begin_state (new_state);
kono
parents:
diff changeset
295 }
kono
parents:
diff changeset
296 }
kono
parents:
diff changeset
297
kono
parents:
diff changeset
298 /* Turn on any colorization for STATE. */
kono
parents:
diff changeset
299
kono
parents:
diff changeset
300 void
kono
parents:
diff changeset
301 colorizer::begin_state (int state)
kono
parents:
diff changeset
302 {
kono
parents:
diff changeset
303 switch (state)
kono
parents:
diff changeset
304 {
kono
parents:
diff changeset
305 case STATE_NORMAL_TEXT:
kono
parents:
diff changeset
306 break;
kono
parents:
diff changeset
307
kono
parents:
diff changeset
308 case STATE_FIXIT_INSERT:
kono
parents:
diff changeset
309 pp_string (m_context->printer, m_fixit_insert);
kono
parents:
diff changeset
310 break;
kono
parents:
diff changeset
311
kono
parents:
diff changeset
312 case STATE_FIXIT_DELETE:
kono
parents:
diff changeset
313 pp_string (m_context->printer, m_fixit_delete);
kono
parents:
diff changeset
314 break;
kono
parents:
diff changeset
315
kono
parents:
diff changeset
316 case 0:
kono
parents:
diff changeset
317 /* Make range 0 be the same color as the "kind" text
kono
parents:
diff changeset
318 (error vs warning vs note). */
kono
parents:
diff changeset
319 pp_string
kono
parents:
diff changeset
320 (m_context->printer,
kono
parents:
diff changeset
321 colorize_start (pp_show_color (m_context->printer),
kono
parents:
diff changeset
322 diagnostic_get_color_for_kind (m_diagnostic_kind)));
kono
parents:
diff changeset
323 break;
kono
parents:
diff changeset
324
kono
parents:
diff changeset
325 case 1:
kono
parents:
diff changeset
326 pp_string (m_context->printer, m_range1);
kono
parents:
diff changeset
327 break;
kono
parents:
diff changeset
328
kono
parents:
diff changeset
329 case 2:
kono
parents:
diff changeset
330 pp_string (m_context->printer, m_range2);
kono
parents:
diff changeset
331 break;
kono
parents:
diff changeset
332
kono
parents:
diff changeset
333 default:
kono
parents:
diff changeset
334 /* For ranges beyond 2, alternate between color 1 and color 2. */
kono
parents:
diff changeset
335 {
kono
parents:
diff changeset
336 gcc_assert (state > 2);
kono
parents:
diff changeset
337 pp_string (m_context->printer,
kono
parents:
diff changeset
338 state % 2 ? m_range1 : m_range2);
kono
parents:
diff changeset
339 }
kono
parents:
diff changeset
340 break;
kono
parents:
diff changeset
341 }
kono
parents:
diff changeset
342 }
kono
parents:
diff changeset
343
kono
parents:
diff changeset
344 /* Turn off any colorization for STATE. */
kono
parents:
diff changeset
345
kono
parents:
diff changeset
346 void
kono
parents:
diff changeset
347 colorizer::finish_state (int state)
kono
parents:
diff changeset
348 {
kono
parents:
diff changeset
349 if (state != STATE_NORMAL_TEXT)
kono
parents:
diff changeset
350 pp_string (m_context->printer, m_stop_color);
kono
parents:
diff changeset
351 }
kono
parents:
diff changeset
352
kono
parents:
diff changeset
353 /* Get the color code for NAME (or the empty string if
kono
parents:
diff changeset
354 colorization is disabled). */
kono
parents:
diff changeset
355
kono
parents:
diff changeset
356 const char *
kono
parents:
diff changeset
357 colorizer::get_color_by_name (const char *name)
kono
parents:
diff changeset
358 {
kono
parents:
diff changeset
359 return colorize_start (pp_show_color (m_context->printer), name);
kono
parents:
diff changeset
360 }
kono
parents:
diff changeset
361
kono
parents:
diff changeset
362 /* Implementation of class layout_range. */
kono
parents:
diff changeset
363
kono
parents:
diff changeset
364 /* The constructor for class layout_range.
kono
parents:
diff changeset
365 Initialize various layout_point fields from expanded_location
kono
parents:
diff changeset
366 equivalents; we've already filtered on file. */
kono
parents:
diff changeset
367
kono
parents:
diff changeset
368 layout_range::layout_range (const expanded_location *start_exploc,
kono
parents:
diff changeset
369 const expanded_location *finish_exploc,
kono
parents:
diff changeset
370 bool show_caret_p,
kono
parents:
diff changeset
371 const expanded_location *caret_exploc)
kono
parents:
diff changeset
372 : m_start (*start_exploc),
kono
parents:
diff changeset
373 m_finish (*finish_exploc),
kono
parents:
diff changeset
374 m_show_caret_p (show_caret_p),
kono
parents:
diff changeset
375 m_caret (*caret_exploc)
kono
parents:
diff changeset
376 {
kono
parents:
diff changeset
377 }
kono
parents:
diff changeset
378
kono
parents:
diff changeset
379 /* Is (column, row) within the given range?
kono
parents:
diff changeset
380 We've already filtered on the file.
kono
parents:
diff changeset
381
kono
parents:
diff changeset
382 Ranges are closed (both limits are within the range).
kono
parents:
diff changeset
383
kono
parents:
diff changeset
384 Example A: a single-line range:
kono
parents:
diff changeset
385 start: (col=22, line=2)
kono
parents:
diff changeset
386 finish: (col=38, line=2)
kono
parents:
diff changeset
387
kono
parents:
diff changeset
388 |00000011111111112222222222333333333344444444444
kono
parents:
diff changeset
389 |34567890123456789012345678901234567890123456789
kono
parents:
diff changeset
390 --+-----------------------------------------------
kono
parents:
diff changeset
391 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
kono
parents:
diff changeset
392 02|bbbbbbbbbbbbbbbbbbbSwwwwwwwwwwwwwwwFaaaaaaaaaaa
kono
parents:
diff changeset
393 03|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
kono
parents:
diff changeset
394
kono
parents:
diff changeset
395 Example B: a multiline range with
kono
parents:
diff changeset
396 start: (col=14, line=3)
kono
parents:
diff changeset
397 finish: (col=08, line=5)
kono
parents:
diff changeset
398
kono
parents:
diff changeset
399 |00000011111111112222222222333333333344444444444
kono
parents:
diff changeset
400 |34567890123456789012345678901234567890123456789
kono
parents:
diff changeset
401 --+-----------------------------------------------
kono
parents:
diff changeset
402 01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
kono
parents:
diff changeset
403 02|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
kono
parents:
diff changeset
404 03|bbbbbbbbbbbSwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
kono
parents:
diff changeset
405 04|wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
kono
parents:
diff changeset
406 05|wwwwwFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
kono
parents:
diff changeset
407 06|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
kono
parents:
diff changeset
408 --+-----------------------------------------------
kono
parents:
diff changeset
409
kono
parents:
diff changeset
410 Legend:
kono
parents:
diff changeset
411 - 'b' indicates a point *before* the range
kono
parents:
diff changeset
412 - 'S' indicates the start of the range
kono
parents:
diff changeset
413 - 'w' indicates a point within the range
kono
parents:
diff changeset
414 - 'F' indicates the finish of the range (which is
kono
parents:
diff changeset
415 within it).
kono
parents:
diff changeset
416 - 'a' indicates a subsequent point *after* the range. */
kono
parents:
diff changeset
417
kono
parents:
diff changeset
418 bool
kono
parents:
diff changeset
419 layout_range::contains_point (int row, int column) const
kono
parents:
diff changeset
420 {
kono
parents:
diff changeset
421 gcc_assert (m_start.m_line <= m_finish.m_line);
kono
parents:
diff changeset
422 /* ...but the equivalent isn't true for the columns;
kono
parents:
diff changeset
423 consider example B in the comment above. */
kono
parents:
diff changeset
424
kono
parents:
diff changeset
425 if (row < m_start.m_line)
kono
parents:
diff changeset
426 /* Points before the first line of the range are
kono
parents:
diff changeset
427 outside it (corresponding to line 01 in example A
kono
parents:
diff changeset
428 and lines 01 and 02 in example B above). */
kono
parents:
diff changeset
429 return false;
kono
parents:
diff changeset
430
kono
parents:
diff changeset
431 if (row == m_start.m_line)
kono
parents:
diff changeset
432 /* On same line as start of range (corresponding
kono
parents:
diff changeset
433 to line 02 in example A and line 03 in example B). */
kono
parents:
diff changeset
434 {
kono
parents:
diff changeset
435 if (column < m_start.m_column)
kono
parents:
diff changeset
436 /* Points on the starting line of the range, but
kono
parents:
diff changeset
437 before the column in which it begins. */
kono
parents:
diff changeset
438 return false;
kono
parents:
diff changeset
439
kono
parents:
diff changeset
440 if (row < m_finish.m_line)
kono
parents:
diff changeset
441 /* This is a multiline range; the point
kono
parents:
diff changeset
442 is within it (corresponds to line 03 in example B
kono
parents:
diff changeset
443 from column 14 onwards) */
kono
parents:
diff changeset
444 return true;
kono
parents:
diff changeset
445 else
kono
parents:
diff changeset
446 {
kono
parents:
diff changeset
447 /* This is a single-line range. */
kono
parents:
diff changeset
448 gcc_assert (row == m_finish.m_line);
kono
parents:
diff changeset
449 return column <= m_finish.m_column;
kono
parents:
diff changeset
450 }
kono
parents:
diff changeset
451 }
kono
parents:
diff changeset
452
kono
parents:
diff changeset
453 /* The point is in a line beyond that containing the
kono
parents:
diff changeset
454 start of the range: lines 03 onwards in example A,
kono
parents:
diff changeset
455 and lines 04 onwards in example B. */
kono
parents:
diff changeset
456 gcc_assert (row > m_start.m_line);
kono
parents:
diff changeset
457
kono
parents:
diff changeset
458 if (row > m_finish.m_line)
kono
parents:
diff changeset
459 /* The point is beyond the final line of the range
kono
parents:
diff changeset
460 (lines 03 onwards in example A, and lines 06 onwards
kono
parents:
diff changeset
461 in example B). */
kono
parents:
diff changeset
462 return false;
kono
parents:
diff changeset
463
kono
parents:
diff changeset
464 if (row < m_finish.m_line)
kono
parents:
diff changeset
465 {
kono
parents:
diff changeset
466 /* The point is in a line that's fully within a multiline
kono
parents:
diff changeset
467 range (e.g. line 04 in example B). */
kono
parents:
diff changeset
468 gcc_assert (m_start.m_line < m_finish.m_line);
kono
parents:
diff changeset
469 return true;
kono
parents:
diff changeset
470 }
kono
parents:
diff changeset
471
kono
parents:
diff changeset
472 gcc_assert (row == m_finish.m_line);
kono
parents:
diff changeset
473
kono
parents:
diff changeset
474 return column <= m_finish.m_column;
kono
parents:
diff changeset
475 }
kono
parents:
diff changeset
476
kono
parents:
diff changeset
477 /* Does this layout_range contain any part of line ROW? */
kono
parents:
diff changeset
478
kono
parents:
diff changeset
479 bool
kono
parents:
diff changeset
480 layout_range::intersects_line_p (int row) const
kono
parents:
diff changeset
481 {
kono
parents:
diff changeset
482 gcc_assert (m_start.m_line <= m_finish.m_line);
kono
parents:
diff changeset
483 if (row < m_start.m_line)
kono
parents:
diff changeset
484 return false;
kono
parents:
diff changeset
485 if (row > m_finish.m_line)
kono
parents:
diff changeset
486 return false;
kono
parents:
diff changeset
487 return true;
kono
parents:
diff changeset
488 }
kono
parents:
diff changeset
489
kono
parents:
diff changeset
490 #if CHECKING_P
kono
parents:
diff changeset
491
kono
parents:
diff changeset
492 /* A helper function for testing layout_range. */
kono
parents:
diff changeset
493
kono
parents:
diff changeset
494 static layout_range
kono
parents:
diff changeset
495 make_range (int start_line, int start_col, int end_line, int end_col)
kono
parents:
diff changeset
496 {
kono
parents:
diff changeset
497 const expanded_location start_exploc
kono
parents:
diff changeset
498 = {"test.c", start_line, start_col, NULL, false};
kono
parents:
diff changeset
499 const expanded_location finish_exploc
kono
parents:
diff changeset
500 = {"test.c", end_line, end_col, NULL, false};
kono
parents:
diff changeset
501 return layout_range (&start_exploc, &finish_exploc, false,
kono
parents:
diff changeset
502 &start_exploc);
kono
parents:
diff changeset
503 }
kono
parents:
diff changeset
504
kono
parents:
diff changeset
505 /* Selftests for layout_range::contains_point and
kono
parents:
diff changeset
506 layout_range::intersects_line_p. */
kono
parents:
diff changeset
507
kono
parents:
diff changeset
508 /* Selftest for layout_range, where the layout_range
kono
parents:
diff changeset
509 is a range with start==end i.e. a single point. */
kono
parents:
diff changeset
510
kono
parents:
diff changeset
511 static void
kono
parents:
diff changeset
512 test_layout_range_for_single_point ()
kono
parents:
diff changeset
513 {
kono
parents:
diff changeset
514 layout_range point = make_range (7, 10, 7, 10);
kono
parents:
diff changeset
515
kono
parents:
diff changeset
516 /* Tests for layout_range::contains_point. */
kono
parents:
diff changeset
517
kono
parents:
diff changeset
518 /* Before the line. */
kono
parents:
diff changeset
519 ASSERT_FALSE (point.contains_point (6, 1));
kono
parents:
diff changeset
520
kono
parents:
diff changeset
521 /* On the line, but before start. */
kono
parents:
diff changeset
522 ASSERT_FALSE (point.contains_point (7, 9));
kono
parents:
diff changeset
523
kono
parents:
diff changeset
524 /* At the point. */
kono
parents:
diff changeset
525 ASSERT_TRUE (point.contains_point (7, 10));
kono
parents:
diff changeset
526
kono
parents:
diff changeset
527 /* On the line, after the point. */
kono
parents:
diff changeset
528 ASSERT_FALSE (point.contains_point (7, 11));
kono
parents:
diff changeset
529
kono
parents:
diff changeset
530 /* After the line. */
kono
parents:
diff changeset
531 ASSERT_FALSE (point.contains_point (8, 1));
kono
parents:
diff changeset
532
kono
parents:
diff changeset
533 /* Tests for layout_range::intersects_line_p. */
kono
parents:
diff changeset
534 ASSERT_FALSE (point.intersects_line_p (6));
kono
parents:
diff changeset
535 ASSERT_TRUE (point.intersects_line_p (7));
kono
parents:
diff changeset
536 ASSERT_FALSE (point.intersects_line_p (8));
kono
parents:
diff changeset
537 }
kono
parents:
diff changeset
538
kono
parents:
diff changeset
539 /* Selftest for layout_range, where the layout_range
kono
parents:
diff changeset
540 is the single-line range shown as "Example A" above. */
kono
parents:
diff changeset
541
kono
parents:
diff changeset
542 static void
kono
parents:
diff changeset
543 test_layout_range_for_single_line ()
kono
parents:
diff changeset
544 {
kono
parents:
diff changeset
545 layout_range example_a = make_range (2, 22, 2, 38);
kono
parents:
diff changeset
546
kono
parents:
diff changeset
547 /* Tests for layout_range::contains_point. */
kono
parents:
diff changeset
548
kono
parents:
diff changeset
549 /* Before the line. */
kono
parents:
diff changeset
550 ASSERT_FALSE (example_a.contains_point (1, 1));
kono
parents:
diff changeset
551
kono
parents:
diff changeset
552 /* On the line, but before start. */
kono
parents:
diff changeset
553 ASSERT_FALSE (example_a.contains_point (2, 21));
kono
parents:
diff changeset
554
kono
parents:
diff changeset
555 /* On the line, at the start. */
kono
parents:
diff changeset
556 ASSERT_TRUE (example_a.contains_point (2, 22));
kono
parents:
diff changeset
557
kono
parents:
diff changeset
558 /* On the line, within the range. */
kono
parents:
diff changeset
559 ASSERT_TRUE (example_a.contains_point (2, 23));
kono
parents:
diff changeset
560
kono
parents:
diff changeset
561 /* On the line, at the end. */
kono
parents:
diff changeset
562 ASSERT_TRUE (example_a.contains_point (2, 38));
kono
parents:
diff changeset
563
kono
parents:
diff changeset
564 /* On the line, after the end. */
kono
parents:
diff changeset
565 ASSERT_FALSE (example_a.contains_point (2, 39));
kono
parents:
diff changeset
566
kono
parents:
diff changeset
567 /* After the line. */
kono
parents:
diff changeset
568 ASSERT_FALSE (example_a.contains_point (2, 39));
kono
parents:
diff changeset
569
kono
parents:
diff changeset
570 /* Tests for layout_range::intersects_line_p. */
kono
parents:
diff changeset
571 ASSERT_FALSE (example_a.intersects_line_p (1));
kono
parents:
diff changeset
572 ASSERT_TRUE (example_a.intersects_line_p (2));
kono
parents:
diff changeset
573 ASSERT_FALSE (example_a.intersects_line_p (3));
kono
parents:
diff changeset
574 }
kono
parents:
diff changeset
575
kono
parents:
diff changeset
576 /* Selftest for layout_range, where the layout_range
kono
parents:
diff changeset
577 is the multi-line range shown as "Example B" above. */
kono
parents:
diff changeset
578
kono
parents:
diff changeset
579 static void
kono
parents:
diff changeset
580 test_layout_range_for_multiple_lines ()
kono
parents:
diff changeset
581 {
kono
parents:
diff changeset
582 layout_range example_b = make_range (3, 14, 5, 8);
kono
parents:
diff changeset
583
kono
parents:
diff changeset
584 /* Tests for layout_range::contains_point. */
kono
parents:
diff changeset
585
kono
parents:
diff changeset
586 /* Before first line. */
kono
parents:
diff changeset
587 ASSERT_FALSE (example_b.contains_point (1, 1));
kono
parents:
diff changeset
588
kono
parents:
diff changeset
589 /* On the first line, but before start. */
kono
parents:
diff changeset
590 ASSERT_FALSE (example_b.contains_point (3, 13));
kono
parents:
diff changeset
591
kono
parents:
diff changeset
592 /* At the start. */
kono
parents:
diff changeset
593 ASSERT_TRUE (example_b.contains_point (3, 14));
kono
parents:
diff changeset
594
kono
parents:
diff changeset
595 /* On the first line, within the range. */
kono
parents:
diff changeset
596 ASSERT_TRUE (example_b.contains_point (3, 15));
kono
parents:
diff changeset
597
kono
parents:
diff changeset
598 /* On an interior line.
kono
parents:
diff changeset
599 The column number should not matter; try various boundary
kono
parents:
diff changeset
600 values. */
kono
parents:
diff changeset
601 ASSERT_TRUE (example_b.contains_point (4, 1));
kono
parents:
diff changeset
602 ASSERT_TRUE (example_b.contains_point (4, 7));
kono
parents:
diff changeset
603 ASSERT_TRUE (example_b.contains_point (4, 8));
kono
parents:
diff changeset
604 ASSERT_TRUE (example_b.contains_point (4, 9));
kono
parents:
diff changeset
605 ASSERT_TRUE (example_b.contains_point (4, 13));
kono
parents:
diff changeset
606 ASSERT_TRUE (example_b.contains_point (4, 14));
kono
parents:
diff changeset
607 ASSERT_TRUE (example_b.contains_point (4, 15));
kono
parents:
diff changeset
608
kono
parents:
diff changeset
609 /* On the final line, before the end. */
kono
parents:
diff changeset
610 ASSERT_TRUE (example_b.contains_point (5, 7));
kono
parents:
diff changeset
611
kono
parents:
diff changeset
612 /* On the final line, at the end. */
kono
parents:
diff changeset
613 ASSERT_TRUE (example_b.contains_point (5, 8));
kono
parents:
diff changeset
614
kono
parents:
diff changeset
615 /* On the final line, after the end. */
kono
parents:
diff changeset
616 ASSERT_FALSE (example_b.contains_point (5, 9));
kono
parents:
diff changeset
617
kono
parents:
diff changeset
618 /* After the line. */
kono
parents:
diff changeset
619 ASSERT_FALSE (example_b.contains_point (6, 1));
kono
parents:
diff changeset
620
kono
parents:
diff changeset
621 /* Tests for layout_range::intersects_line_p. */
kono
parents:
diff changeset
622 ASSERT_FALSE (example_b.intersects_line_p (2));
kono
parents:
diff changeset
623 ASSERT_TRUE (example_b.intersects_line_p (3));
kono
parents:
diff changeset
624 ASSERT_TRUE (example_b.intersects_line_p (4));
kono
parents:
diff changeset
625 ASSERT_TRUE (example_b.intersects_line_p (5));
kono
parents:
diff changeset
626 ASSERT_FALSE (example_b.intersects_line_p (6));
kono
parents:
diff changeset
627 }
kono
parents:
diff changeset
628
kono
parents:
diff changeset
629 #endif /* #if CHECKING_P */
kono
parents:
diff changeset
630
kono
parents:
diff changeset
631 /* Given a source line LINE of length LINE_WIDTH, determine the width
kono
parents:
diff changeset
632 without any trailing whitespace. */
kono
parents:
diff changeset
633
kono
parents:
diff changeset
634 static int
kono
parents:
diff changeset
635 get_line_width_without_trailing_whitespace (const char *line, int line_width)
kono
parents:
diff changeset
636 {
kono
parents:
diff changeset
637 int result = line_width;
kono
parents:
diff changeset
638 while (result > 0)
kono
parents:
diff changeset
639 {
kono
parents:
diff changeset
640 char ch = line[result - 1];
kono
parents:
diff changeset
641 if (ch == ' ' || ch == '\t')
kono
parents:
diff changeset
642 result--;
kono
parents:
diff changeset
643 else
kono
parents:
diff changeset
644 break;
kono
parents:
diff changeset
645 }
kono
parents:
diff changeset
646 gcc_assert (result >= 0);
kono
parents:
diff changeset
647 gcc_assert (result <= line_width);
kono
parents:
diff changeset
648 gcc_assert (result == 0 ||
kono
parents:
diff changeset
649 (line[result - 1] != ' '
kono
parents:
diff changeset
650 && line[result -1] != '\t'));
kono
parents:
diff changeset
651 return result;
kono
parents:
diff changeset
652 }
kono
parents:
diff changeset
653
kono
parents:
diff changeset
654 #if CHECKING_P
kono
parents:
diff changeset
655
kono
parents:
diff changeset
656 /* A helper function for testing get_line_width_without_trailing_whitespace. */
kono
parents:
diff changeset
657
kono
parents:
diff changeset
658 static void
kono
parents:
diff changeset
659 assert_eq (const char *line, int expected_width)
kono
parents:
diff changeset
660 {
kono
parents:
diff changeset
661 int actual_value
kono
parents:
diff changeset
662 = get_line_width_without_trailing_whitespace (line, strlen (line));
kono
parents:
diff changeset
663 ASSERT_EQ (actual_value, expected_width);
kono
parents:
diff changeset
664 }
kono
parents:
diff changeset
665
kono
parents:
diff changeset
666 /* Verify that get_line_width_without_trailing_whitespace is sane for
kono
parents:
diff changeset
667 various inputs. It is not required to handle newlines. */
kono
parents:
diff changeset
668
kono
parents:
diff changeset
669 static void
kono
parents:
diff changeset
670 test_get_line_width_without_trailing_whitespace ()
kono
parents:
diff changeset
671 {
kono
parents:
diff changeset
672 assert_eq ("", 0);
kono
parents:
diff changeset
673 assert_eq (" ", 0);
kono
parents:
diff changeset
674 assert_eq ("\t", 0);
kono
parents:
diff changeset
675 assert_eq ("hello world", 11);
kono
parents:
diff changeset
676 assert_eq ("hello world ", 11);
kono
parents:
diff changeset
677 assert_eq ("hello world \t\t ", 11);
kono
parents:
diff changeset
678 }
kono
parents:
diff changeset
679
kono
parents:
diff changeset
680 #endif /* #if CHECKING_P */
kono
parents:
diff changeset
681
kono
parents:
diff changeset
682 /* Helper function for layout's ctor, for sanitizing locations relative
kono
parents:
diff changeset
683 to the primary location within a diagnostic.
kono
parents:
diff changeset
684
kono
parents:
diff changeset
685 Compare LOC_A and LOC_B to see if it makes sense to print underlines
kono
parents:
diff changeset
686 connecting their expanded locations. Doing so is only guaranteed to
kono
parents:
diff changeset
687 make sense if the locations share the same macro expansion "history"
kono
parents:
diff changeset
688 i.e. they can be traced through the same macro expansions, eventually
kono
parents:
diff changeset
689 reaching an ordinary map.
kono
parents:
diff changeset
690
kono
parents:
diff changeset
691 This may be too strong a condition, but it effectively sanitizes
kono
parents:
diff changeset
692 PR c++/70105, which has an example of printing an expression where the
kono
parents:
diff changeset
693 final location of the expression is in a different macro, which
kono
parents:
diff changeset
694 erroneously was leading to hundreds of lines of irrelevant source
kono
parents:
diff changeset
695 being printed. */
kono
parents:
diff changeset
696
kono
parents:
diff changeset
697 static bool
kono
parents:
diff changeset
698 compatible_locations_p (location_t loc_a, location_t loc_b)
kono
parents:
diff changeset
699 {
kono
parents:
diff changeset
700 if (IS_ADHOC_LOC (loc_a))
kono
parents:
diff changeset
701 loc_a = get_location_from_adhoc_loc (line_table, loc_a);
kono
parents:
diff changeset
702 if (IS_ADHOC_LOC (loc_b))
kono
parents:
diff changeset
703 loc_b = get_location_from_adhoc_loc (line_table, loc_b);
kono
parents:
diff changeset
704
kono
parents:
diff changeset
705 /* If either location is one of the special locations outside of a
kono
parents:
diff changeset
706 linemap, they are only compatible if they are equal. */
kono
parents:
diff changeset
707 if (loc_a < RESERVED_LOCATION_COUNT
kono
parents:
diff changeset
708 || loc_b < RESERVED_LOCATION_COUNT)
kono
parents:
diff changeset
709 return loc_a == loc_b;
kono
parents:
diff changeset
710
kono
parents:
diff changeset
711 const line_map *map_a = linemap_lookup (line_table, loc_a);
kono
parents:
diff changeset
712 linemap_assert (map_a);
kono
parents:
diff changeset
713
kono
parents:
diff changeset
714 const line_map *map_b = linemap_lookup (line_table, loc_b);
kono
parents:
diff changeset
715 linemap_assert (map_b);
kono
parents:
diff changeset
716
kono
parents:
diff changeset
717 /* Are they within the same map? */
kono
parents:
diff changeset
718 if (map_a == map_b)
kono
parents:
diff changeset
719 {
kono
parents:
diff changeset
720 /* Are both within the same macro expansion? */
kono
parents:
diff changeset
721 if (linemap_macro_expansion_map_p (map_a))
kono
parents:
diff changeset
722 {
kono
parents:
diff changeset
723 /* Expand each location towards the spelling location, and
kono
parents:
diff changeset
724 recurse. */
kono
parents:
diff changeset
725 const line_map_macro *macro_map = linemap_check_macro (map_a);
kono
parents:
diff changeset
726 source_location loc_a_toward_spelling
kono
parents:
diff changeset
727 = linemap_macro_map_loc_unwind_toward_spelling (line_table,
kono
parents:
diff changeset
728 macro_map,
kono
parents:
diff changeset
729 loc_a);
kono
parents:
diff changeset
730 source_location loc_b_toward_spelling
kono
parents:
diff changeset
731 = linemap_macro_map_loc_unwind_toward_spelling (line_table,
kono
parents:
diff changeset
732 macro_map,
kono
parents:
diff changeset
733 loc_b);
kono
parents:
diff changeset
734 return compatible_locations_p (loc_a_toward_spelling,
kono
parents:
diff changeset
735 loc_b_toward_spelling);
kono
parents:
diff changeset
736 }
kono
parents:
diff changeset
737
kono
parents:
diff changeset
738 /* Otherwise they are within the same ordinary map. */
kono
parents:
diff changeset
739 return true;
kono
parents:
diff changeset
740 }
kono
parents:
diff changeset
741 else
kono
parents:
diff changeset
742 {
kono
parents:
diff changeset
743 /* Within different maps. */
kono
parents:
diff changeset
744
kono
parents:
diff changeset
745 /* If either is within a macro expansion, they are incompatible. */
kono
parents:
diff changeset
746 if (linemap_macro_expansion_map_p (map_a)
kono
parents:
diff changeset
747 || linemap_macro_expansion_map_p (map_b))
kono
parents:
diff changeset
748 return false;
kono
parents:
diff changeset
749
kono
parents:
diff changeset
750 /* Within two different ordinary maps; they are compatible iff they
kono
parents:
diff changeset
751 are in the same file. */
kono
parents:
diff changeset
752 const line_map_ordinary *ord_map_a = linemap_check_ordinary (map_a);
kono
parents:
diff changeset
753 const line_map_ordinary *ord_map_b = linemap_check_ordinary (map_b);
kono
parents:
diff changeset
754 return ord_map_a->to_file == ord_map_b->to_file;
kono
parents:
diff changeset
755 }
kono
parents:
diff changeset
756 }
kono
parents:
diff changeset
757
kono
parents:
diff changeset
758 /* Comparator for sorting fix-it hints. */
kono
parents:
diff changeset
759
kono
parents:
diff changeset
760 static int
kono
parents:
diff changeset
761 fixit_cmp (const void *p_a, const void *p_b)
kono
parents:
diff changeset
762 {
kono
parents:
diff changeset
763 const fixit_hint * hint_a = *static_cast<const fixit_hint * const *> (p_a);
kono
parents:
diff changeset
764 const fixit_hint * hint_b = *static_cast<const fixit_hint * const *> (p_b);
kono
parents:
diff changeset
765 return hint_a->get_start_loc () - hint_b->get_start_loc ();
kono
parents:
diff changeset
766 }
kono
parents:
diff changeset
767
kono
parents:
diff changeset
768 /* Implementation of class layout. */
kono
parents:
diff changeset
769
kono
parents:
diff changeset
770 /* Constructor for class layout.
kono
parents:
diff changeset
771
kono
parents:
diff changeset
772 Filter the ranges from the rich_location to those that we can
kono
parents:
diff changeset
773 sanely print, populating m_layout_ranges and m_fixit_hints.
kono
parents:
diff changeset
774 Determine the range of lines that we will print, splitting them
kono
parents:
diff changeset
775 up into an ordered list of disjoint spans of contiguous line numbers.
kono
parents:
diff changeset
776 Determine m_x_offset, to ensure that the primary caret
kono
parents:
diff changeset
777 will fit within the max_width provided by the diagnostic_context. */
kono
parents:
diff changeset
778
kono
parents:
diff changeset
779 layout::layout (diagnostic_context * context,
kono
parents:
diff changeset
780 rich_location *richloc,
kono
parents:
diff changeset
781 diagnostic_t diagnostic_kind)
kono
parents:
diff changeset
782 : m_context (context),
kono
parents:
diff changeset
783 m_pp (context->printer),
kono
parents:
diff changeset
784 m_diagnostic_kind (diagnostic_kind),
kono
parents:
diff changeset
785 m_primary_loc (richloc->get_range (0)->m_loc),
kono
parents:
diff changeset
786 m_exploc (richloc->get_expanded_location (0)),
kono
parents:
diff changeset
787 m_colorizer (context, diagnostic_kind),
kono
parents:
diff changeset
788 m_colorize_source_p (context->colorize_source_p),
kono
parents:
diff changeset
789 m_layout_ranges (richloc->get_num_locations ()),
kono
parents:
diff changeset
790 m_fixit_hints (richloc->get_num_fixit_hints ()),
kono
parents:
diff changeset
791 m_line_spans (1 + richloc->get_num_locations ()),
kono
parents:
diff changeset
792 m_x_offset (0)
kono
parents:
diff changeset
793 {
kono
parents:
diff changeset
794 for (unsigned int idx = 0; idx < richloc->get_num_locations (); idx++)
kono
parents:
diff changeset
795 {
kono
parents:
diff changeset
796 /* This diagnostic printer can only cope with "sufficiently sane" ranges.
kono
parents:
diff changeset
797 Ignore any ranges that are awkward to handle. */
kono
parents:
diff changeset
798 const location_range *loc_range = richloc->get_range (idx);
kono
parents:
diff changeset
799 maybe_add_location_range (loc_range, false);
kono
parents:
diff changeset
800 }
kono
parents:
diff changeset
801
kono
parents:
diff changeset
802 /* Populate m_fixit_hints, filtering to only those that are in the
kono
parents:
diff changeset
803 same file. */
kono
parents:
diff changeset
804 for (unsigned int i = 0; i < richloc->get_num_fixit_hints (); i++)
kono
parents:
diff changeset
805 {
kono
parents:
diff changeset
806 const fixit_hint *hint = richloc->get_fixit_hint (i);
kono
parents:
diff changeset
807 if (validate_fixit_hint_p (hint))
kono
parents:
diff changeset
808 m_fixit_hints.safe_push (hint);
kono
parents:
diff changeset
809 }
kono
parents:
diff changeset
810
kono
parents:
diff changeset
811 /* Sort m_fixit_hints. */
kono
parents:
diff changeset
812 m_fixit_hints.qsort (fixit_cmp);
kono
parents:
diff changeset
813
kono
parents:
diff changeset
814 /* Populate m_line_spans. */
kono
parents:
diff changeset
815 calculate_line_spans ();
kono
parents:
diff changeset
816
kono
parents:
diff changeset
817 /* Adjust m_x_offset.
kono
parents:
diff changeset
818 Center the primary caret to fit in max_width; all columns
kono
parents:
diff changeset
819 will be adjusted accordingly. */
kono
parents:
diff changeset
820 int max_width = m_context->caret_max_width;
kono
parents:
diff changeset
821 int line_width;
kono
parents:
diff changeset
822 const char *line = location_get_source_line (m_exploc.file, m_exploc.line,
kono
parents:
diff changeset
823 &line_width);
kono
parents:
diff changeset
824 if (line && m_exploc.column <= line_width)
kono
parents:
diff changeset
825 {
kono
parents:
diff changeset
826 int right_margin = CARET_LINE_MARGIN;
kono
parents:
diff changeset
827 int column = m_exploc.column;
kono
parents:
diff changeset
828 right_margin = MIN (line_width - column, right_margin);
kono
parents:
diff changeset
829 right_margin = max_width - right_margin;
kono
parents:
diff changeset
830 if (line_width >= max_width && column > right_margin)
kono
parents:
diff changeset
831 m_x_offset = column - right_margin;
kono
parents:
diff changeset
832 gcc_assert (m_x_offset >= 0);
kono
parents:
diff changeset
833 }
kono
parents:
diff changeset
834
kono
parents:
diff changeset
835 if (context->show_ruler_p)
kono
parents:
diff changeset
836 show_ruler (m_x_offset + max_width);
kono
parents:
diff changeset
837 }
kono
parents:
diff changeset
838
kono
parents:
diff changeset
839 /* Attempt to add LOC_RANGE to m_layout_ranges, filtering them to
kono
parents:
diff changeset
840 those that we can sanely print.
kono
parents:
diff changeset
841
kono
parents:
diff changeset
842 If RESTRICT_TO_CURRENT_LINE_SPANS is true, then LOC_RANGE is also
kono
parents:
diff changeset
843 filtered against this layout instance's current line spans: it
kono
parents:
diff changeset
844 will only be added if the location is fully within the lines
kono
parents:
diff changeset
845 already specified by other locations.
kono
parents:
diff changeset
846
kono
parents:
diff changeset
847 Return true iff LOC_RANGE was added. */
kono
parents:
diff changeset
848
kono
parents:
diff changeset
849 bool
kono
parents:
diff changeset
850 layout::maybe_add_location_range (const location_range *loc_range,
kono
parents:
diff changeset
851 bool restrict_to_current_line_spans)
kono
parents:
diff changeset
852 {
kono
parents:
diff changeset
853 gcc_assert (loc_range);
kono
parents:
diff changeset
854
kono
parents:
diff changeset
855 /* Split the "range" into caret and range information. */
kono
parents:
diff changeset
856 source_range src_range = get_range_from_loc (line_table, loc_range->m_loc);
kono
parents:
diff changeset
857
kono
parents:
diff changeset
858 /* Expand the various locations. */
kono
parents:
diff changeset
859 expanded_location start
kono
parents:
diff changeset
860 = linemap_client_expand_location_to_spelling_point
kono
parents:
diff changeset
861 (src_range.m_start, LOCATION_ASPECT_START);
kono
parents:
diff changeset
862 expanded_location finish
kono
parents:
diff changeset
863 = linemap_client_expand_location_to_spelling_point
kono
parents:
diff changeset
864 (src_range.m_finish, LOCATION_ASPECT_FINISH);
kono
parents:
diff changeset
865 expanded_location caret
kono
parents:
diff changeset
866 = linemap_client_expand_location_to_spelling_point
kono
parents:
diff changeset
867 (loc_range->m_loc, LOCATION_ASPECT_CARET);
kono
parents:
diff changeset
868
kono
parents:
diff changeset
869 /* If any part of the range isn't in the same file as the primary
kono
parents:
diff changeset
870 location of this diagnostic, ignore the range. */
kono
parents:
diff changeset
871 if (start.file != m_exploc.file)
kono
parents:
diff changeset
872 return false;
kono
parents:
diff changeset
873 if (finish.file != m_exploc.file)
kono
parents:
diff changeset
874 return false;
kono
parents:
diff changeset
875 if (loc_range->m_show_caret_p)
kono
parents:
diff changeset
876 if (caret.file != m_exploc.file)
kono
parents:
diff changeset
877 return false;
kono
parents:
diff changeset
878
kono
parents:
diff changeset
879 /* Sanitize the caret location for non-primary ranges. */
kono
parents:
diff changeset
880 if (m_layout_ranges.length () > 0)
kono
parents:
diff changeset
881 if (loc_range->m_show_caret_p)
kono
parents:
diff changeset
882 if (!compatible_locations_p (loc_range->m_loc, m_primary_loc))
kono
parents:
diff changeset
883 /* Discard any non-primary ranges that can't be printed
kono
parents:
diff changeset
884 sanely relative to the primary location. */
kono
parents:
diff changeset
885 return false;
kono
parents:
diff changeset
886
kono
parents:
diff changeset
887 /* Everything is now known to be in the correct source file,
kono
parents:
diff changeset
888 but it may require further sanitization. */
kono
parents:
diff changeset
889 layout_range ri (&start, &finish, loc_range->m_show_caret_p, &caret);
kono
parents:
diff changeset
890
kono
parents:
diff changeset
891 /* If we have a range that finishes before it starts (perhaps
kono
parents:
diff changeset
892 from something built via macro expansion), printing the
kono
parents:
diff changeset
893 range is likely to be nonsensical. Also, attempting to do so
kono
parents:
diff changeset
894 breaks assumptions within the printing code (PR c/68473).
kono
parents:
diff changeset
895 Similarly, don't attempt to print ranges if one or both ends
kono
parents:
diff changeset
896 of the range aren't sane to print relative to the
kono
parents:
diff changeset
897 primary location (PR c++/70105). */
kono
parents:
diff changeset
898 if (start.line > finish.line
kono
parents:
diff changeset
899 || !compatible_locations_p (src_range.m_start, m_primary_loc)
kono
parents:
diff changeset
900 || !compatible_locations_p (src_range.m_finish, m_primary_loc))
kono
parents:
diff changeset
901 {
kono
parents:
diff changeset
902 /* Is this the primary location? */
kono
parents:
diff changeset
903 if (m_layout_ranges.length () == 0)
kono
parents:
diff changeset
904 {
kono
parents:
diff changeset
905 /* We want to print the caret for the primary location, but
kono
parents:
diff changeset
906 we must sanitize away m_start and m_finish. */
kono
parents:
diff changeset
907 ri.m_start = ri.m_caret;
kono
parents:
diff changeset
908 ri.m_finish = ri.m_caret;
kono
parents:
diff changeset
909 }
kono
parents:
diff changeset
910 else
kono
parents:
diff changeset
911 /* This is a non-primary range; ignore it. */
kono
parents:
diff changeset
912 return false;
kono
parents:
diff changeset
913 }
kono
parents:
diff changeset
914
kono
parents:
diff changeset
915 /* Potentially filter to just the lines already specified by other
kono
parents:
diff changeset
916 locations. This is for use by gcc_rich_location::add_location_if_nearby.
kono
parents:
diff changeset
917 The layout ctor doesn't use it, and can't because m_line_spans
kono
parents:
diff changeset
918 hasn't been set up at that point. */
kono
parents:
diff changeset
919 if (restrict_to_current_line_spans)
kono
parents:
diff changeset
920 {
kono
parents:
diff changeset
921 if (!will_show_line_p (start.line))
kono
parents:
diff changeset
922 return false;
kono
parents:
diff changeset
923 if (!will_show_line_p (finish.line))
kono
parents:
diff changeset
924 return false;
kono
parents:
diff changeset
925 if (loc_range->m_show_caret_p)
kono
parents:
diff changeset
926 if (!will_show_line_p (caret.line))
kono
parents:
diff changeset
927 return false;
kono
parents:
diff changeset
928 }
kono
parents:
diff changeset
929
kono
parents:
diff changeset
930 /* Passed all the tests; add the range to m_layout_ranges so that
kono
parents:
diff changeset
931 it will be printed. */
kono
parents:
diff changeset
932 m_layout_ranges.safe_push (ri);
kono
parents:
diff changeset
933 return true;
kono
parents:
diff changeset
934 }
kono
parents:
diff changeset
935
kono
parents:
diff changeset
936 /* Return true iff ROW is within one of the line spans for this layout. */
kono
parents:
diff changeset
937
kono
parents:
diff changeset
938 bool
kono
parents:
diff changeset
939 layout::will_show_line_p (int row) const
kono
parents:
diff changeset
940 {
kono
parents:
diff changeset
941 for (int line_span_idx = 0; line_span_idx < get_num_line_spans ();
kono
parents:
diff changeset
942 line_span_idx++)
kono
parents:
diff changeset
943 {
kono
parents:
diff changeset
944 const line_span *line_span = get_line_span (line_span_idx);
kono
parents:
diff changeset
945 if (line_span->contains_line_p (row))
kono
parents:
diff changeset
946 return true;
kono
parents:
diff changeset
947 }
kono
parents:
diff changeset
948 return false;
kono
parents:
diff changeset
949 }
kono
parents:
diff changeset
950
kono
parents:
diff changeset
951 /* Return true iff we should print a heading when starting the
kono
parents:
diff changeset
952 line span with the given index. */
kono
parents:
diff changeset
953
kono
parents:
diff changeset
954 bool
kono
parents:
diff changeset
955 layout::print_heading_for_line_span_index_p (int line_span_idx) const
kono
parents:
diff changeset
956 {
kono
parents:
diff changeset
957 /* We print a heading for every change of line span, hence for every
kono
parents:
diff changeset
958 line span after the initial one. */
kono
parents:
diff changeset
959 if (line_span_idx > 0)
kono
parents:
diff changeset
960 return true;
kono
parents:
diff changeset
961
kono
parents:
diff changeset
962 /* We also do it for the initial span if the primary location of the
kono
parents:
diff changeset
963 diagnostic is in a different span. */
kono
parents:
diff changeset
964 if (m_exploc.line > (int)get_line_span (0)->m_last_line)
kono
parents:
diff changeset
965 return true;
kono
parents:
diff changeset
966
kono
parents:
diff changeset
967 return false;
kono
parents:
diff changeset
968 }
kono
parents:
diff changeset
969
kono
parents:
diff changeset
970 /* Get an expanded_location for the first location of interest within
kono
parents:
diff changeset
971 the given line_span.
kono
parents:
diff changeset
972 Used when printing a heading to indicate a new line span. */
kono
parents:
diff changeset
973
kono
parents:
diff changeset
974 expanded_location
kono
parents:
diff changeset
975 layout::get_expanded_location (const line_span *line_span) const
kono
parents:
diff changeset
976 {
kono
parents:
diff changeset
977 /* Whenever possible, use the caret location. */
kono
parents:
diff changeset
978 if (line_span->contains_line_p (m_exploc.line))
kono
parents:
diff changeset
979 return m_exploc;
kono
parents:
diff changeset
980
kono
parents:
diff changeset
981 /* Otherwise, use the start of the first range that's present
kono
parents:
diff changeset
982 within the line_span. */
kono
parents:
diff changeset
983 for (unsigned int i = 0; i < m_layout_ranges.length (); i++)
kono
parents:
diff changeset
984 {
kono
parents:
diff changeset
985 const layout_range *lr = &m_layout_ranges[i];
kono
parents:
diff changeset
986 if (line_span->contains_line_p (lr->m_start.m_line))
kono
parents:
diff changeset
987 {
kono
parents:
diff changeset
988 expanded_location exploc = m_exploc;
kono
parents:
diff changeset
989 exploc.line = lr->m_start.m_line;
kono
parents:
diff changeset
990 exploc.column = lr->m_start.m_column;
kono
parents:
diff changeset
991 return exploc;
kono
parents:
diff changeset
992 }
kono
parents:
diff changeset
993 }
kono
parents:
diff changeset
994
kono
parents:
diff changeset
995 /* Otherwise, use the location of the first fixit-hint present within
kono
parents:
diff changeset
996 the line_span. */
kono
parents:
diff changeset
997 for (unsigned int i = 0; i < m_fixit_hints.length (); i++)
kono
parents:
diff changeset
998 {
kono
parents:
diff changeset
999 const fixit_hint *hint = m_fixit_hints[i];
kono
parents:
diff changeset
1000 location_t loc = hint->get_start_loc ();
kono
parents:
diff changeset
1001 expanded_location exploc = expand_location (loc);
kono
parents:
diff changeset
1002 if (line_span->contains_line_p (exploc.line))
kono
parents:
diff changeset
1003 return exploc;
kono
parents:
diff changeset
1004 }
kono
parents:
diff changeset
1005
kono
parents:
diff changeset
1006 /* It should not be possible to have a line span that didn't
kono
parents:
diff changeset
1007 contain any of the layout_range or fixit_hint instances. */
kono
parents:
diff changeset
1008 gcc_unreachable ();
kono
parents:
diff changeset
1009 return m_exploc;
kono
parents:
diff changeset
1010 }
kono
parents:
diff changeset
1011
kono
parents:
diff changeset
1012 /* Determine if HINT is meaningful to print within this layout. */
kono
parents:
diff changeset
1013
kono
parents:
diff changeset
1014 bool
kono
parents:
diff changeset
1015 layout::validate_fixit_hint_p (const fixit_hint *hint)
kono
parents:
diff changeset
1016 {
kono
parents:
diff changeset
1017 if (LOCATION_FILE (hint->get_start_loc ()) != m_exploc.file)
kono
parents:
diff changeset
1018 return false;
kono
parents:
diff changeset
1019 if (LOCATION_FILE (hint->get_next_loc ()) != m_exploc.file)
kono
parents:
diff changeset
1020 return false;
kono
parents:
diff changeset
1021
kono
parents:
diff changeset
1022 return true;
kono
parents:
diff changeset
1023 }
kono
parents:
diff changeset
1024
kono
parents:
diff changeset
1025 /* Determine the range of lines affected by HINT.
kono
parents:
diff changeset
1026 This assumes that HINT has already been filtered by
kono
parents:
diff changeset
1027 validate_fixit_hint_p, and so affects the correct source file. */
kono
parents:
diff changeset
1028
kono
parents:
diff changeset
1029 static line_span
kono
parents:
diff changeset
1030 get_line_span_for_fixit_hint (const fixit_hint *hint)
kono
parents:
diff changeset
1031 {
kono
parents:
diff changeset
1032 gcc_assert (hint);
kono
parents:
diff changeset
1033 return line_span (LOCATION_LINE (hint->get_start_loc ()),
kono
parents:
diff changeset
1034 LOCATION_LINE (hint->get_next_loc ()));
kono
parents:
diff changeset
1035 }
kono
parents:
diff changeset
1036
kono
parents:
diff changeset
1037 /* We want to print the pertinent source code at a diagnostic. The
kono
parents:
diff changeset
1038 rich_location can contain multiple locations. This will have been
kono
parents:
diff changeset
1039 filtered into m_exploc (the caret for the primary location) and
kono
parents:
diff changeset
1040 m_layout_ranges, for those ranges within the same source file.
kono
parents:
diff changeset
1041
kono
parents:
diff changeset
1042 We will print a subset of the lines within the source file in question,
kono
parents:
diff changeset
1043 as a collection of "spans" of lines.
kono
parents:
diff changeset
1044
kono
parents:
diff changeset
1045 This function populates m_line_spans with an ordered, disjoint list of
kono
parents:
diff changeset
1046 the line spans of interest.
kono
parents:
diff changeset
1047
kono
parents:
diff changeset
1048 For example, if the primary caret location is on line 7, with ranges
kono
parents:
diff changeset
1049 covering lines 5-6 and lines 9-12:
kono
parents:
diff changeset
1050
kono
parents:
diff changeset
1051 004
kono
parents:
diff changeset
1052 005 |RANGE 0
kono
parents:
diff changeset
1053 006 |RANGE 0
kono
parents:
diff changeset
1054 007 |PRIMARY CARET
kono
parents:
diff changeset
1055 008
kono
parents:
diff changeset
1056 009 |RANGE 1
kono
parents:
diff changeset
1057 010 |RANGE 1
kono
parents:
diff changeset
1058 011 |RANGE 1
kono
parents:
diff changeset
1059 012 |RANGE 1
kono
parents:
diff changeset
1060 013
kono
parents:
diff changeset
1061
kono
parents:
diff changeset
1062 then we want two spans: lines 5-7 and lines 9-12. */
kono
parents:
diff changeset
1063
kono
parents:
diff changeset
1064 void
kono
parents:
diff changeset
1065 layout::calculate_line_spans ()
kono
parents:
diff changeset
1066 {
kono
parents:
diff changeset
1067 /* This should only be called once, by the ctor. */
kono
parents:
diff changeset
1068 gcc_assert (m_line_spans.length () == 0);
kono
parents:
diff changeset
1069
kono
parents:
diff changeset
1070 /* Populate tmp_spans with individual spans, for each of
kono
parents:
diff changeset
1071 m_exploc, and for m_layout_ranges. */
kono
parents:
diff changeset
1072 auto_vec<line_span> tmp_spans (1 + m_layout_ranges.length ());
kono
parents:
diff changeset
1073 tmp_spans.safe_push (line_span (m_exploc.line, m_exploc.line));
kono
parents:
diff changeset
1074 for (unsigned int i = 0; i < m_layout_ranges.length (); i++)
kono
parents:
diff changeset
1075 {
kono
parents:
diff changeset
1076 const layout_range *lr = &m_layout_ranges[i];
kono
parents:
diff changeset
1077 gcc_assert (lr->m_start.m_line <= lr->m_finish.m_line);
kono
parents:
diff changeset
1078 tmp_spans.safe_push (line_span (lr->m_start.m_line,
kono
parents:
diff changeset
1079 lr->m_finish.m_line));
kono
parents:
diff changeset
1080 }
kono
parents:
diff changeset
1081
kono
parents:
diff changeset
1082 /* Also add spans for any fix-it hints, in case they cover other lines. */
kono
parents:
diff changeset
1083 for (unsigned int i = 0; i < m_fixit_hints.length (); i++)
kono
parents:
diff changeset
1084 {
kono
parents:
diff changeset
1085 const fixit_hint *hint = m_fixit_hints[i];
kono
parents:
diff changeset
1086 gcc_assert (hint);
kono
parents:
diff changeset
1087 tmp_spans.safe_push (get_line_span_for_fixit_hint (hint));
kono
parents:
diff changeset
1088 }
kono
parents:
diff changeset
1089
kono
parents:
diff changeset
1090 /* Sort them. */
kono
parents:
diff changeset
1091 tmp_spans.qsort(line_span::comparator);
kono
parents:
diff changeset
1092
kono
parents:
diff changeset
1093 /* Now iterate through tmp_spans, copying into m_line_spans, and
kono
parents:
diff changeset
1094 combining where possible. */
kono
parents:
diff changeset
1095 gcc_assert (tmp_spans.length () > 0);
kono
parents:
diff changeset
1096 m_line_spans.safe_push (tmp_spans[0]);
kono
parents:
diff changeset
1097 for (unsigned int i = 1; i < tmp_spans.length (); i++)
kono
parents:
diff changeset
1098 {
kono
parents:
diff changeset
1099 line_span *current = &m_line_spans[m_line_spans.length () - 1];
kono
parents:
diff changeset
1100 const line_span *next = &tmp_spans[i];
kono
parents:
diff changeset
1101 gcc_assert (next->m_first_line >= current->m_first_line);
kono
parents:
diff changeset
1102 if (next->m_first_line <= current->m_last_line + 1)
kono
parents:
diff changeset
1103 {
kono
parents:
diff changeset
1104 /* We can merge them. */
kono
parents:
diff changeset
1105 if (next->m_last_line > current->m_last_line)
kono
parents:
diff changeset
1106 current->m_last_line = next->m_last_line;
kono
parents:
diff changeset
1107 }
kono
parents:
diff changeset
1108 else
kono
parents:
diff changeset
1109 {
kono
parents:
diff changeset
1110 /* No merger possible. */
kono
parents:
diff changeset
1111 m_line_spans.safe_push (*next);
kono
parents:
diff changeset
1112 }
kono
parents:
diff changeset
1113 }
kono
parents:
diff changeset
1114
kono
parents:
diff changeset
1115 /* Verify the result, in m_line_spans. */
kono
parents:
diff changeset
1116 gcc_assert (m_line_spans.length () > 0);
kono
parents:
diff changeset
1117 for (unsigned int i = 1; i < m_line_spans.length (); i++)
kono
parents:
diff changeset
1118 {
kono
parents:
diff changeset
1119 const line_span *prev = &m_line_spans[i - 1];
kono
parents:
diff changeset
1120 const line_span *next = &m_line_spans[i];
kono
parents:
diff changeset
1121 /* The individual spans must be sane. */
kono
parents:
diff changeset
1122 gcc_assert (prev->m_first_line <= prev->m_last_line);
kono
parents:
diff changeset
1123 gcc_assert (next->m_first_line <= next->m_last_line);
kono
parents:
diff changeset
1124 /* The spans must be ordered. */
kono
parents:
diff changeset
1125 gcc_assert (prev->m_first_line < next->m_first_line);
kono
parents:
diff changeset
1126 /* There must be a gap of at least one line between separate spans. */
kono
parents:
diff changeset
1127 gcc_assert ((prev->m_last_line + 1) < next->m_first_line);
kono
parents:
diff changeset
1128 }
kono
parents:
diff changeset
1129 }
kono
parents:
diff changeset
1130
kono
parents:
diff changeset
1131 /* Print line ROW of source code, potentially colorized at any ranges, and
kono
parents:
diff changeset
1132 populate *LBOUNDS_OUT.
kono
parents:
diff changeset
1133 LINE is the source line (not necessarily 0-terminated) and LINE_WIDTH
kono
parents:
diff changeset
1134 is its width. */
kono
parents:
diff changeset
1135
kono
parents:
diff changeset
1136 void
kono
parents:
diff changeset
1137 layout::print_source_line (int row, const char *line, int line_width,
kono
parents:
diff changeset
1138 line_bounds *lbounds_out)
kono
parents:
diff changeset
1139 {
kono
parents:
diff changeset
1140 m_colorizer.set_normal_text ();
kono
parents:
diff changeset
1141
kono
parents:
diff changeset
1142 /* We will stop printing the source line at any trailing
kono
parents:
diff changeset
1143 whitespace. */
kono
parents:
diff changeset
1144 line_width = get_line_width_without_trailing_whitespace (line,
kono
parents:
diff changeset
1145 line_width);
kono
parents:
diff changeset
1146 line += m_x_offset;
kono
parents:
diff changeset
1147
kono
parents:
diff changeset
1148 pp_space (m_pp);
kono
parents:
diff changeset
1149 int first_non_ws = INT_MAX;
kono
parents:
diff changeset
1150 int last_non_ws = 0;
kono
parents:
diff changeset
1151 int column;
kono
parents:
diff changeset
1152 for (column = 1 + m_x_offset; column <= line_width; column++)
kono
parents:
diff changeset
1153 {
kono
parents:
diff changeset
1154 /* Assuming colorization is enabled for the caret and underline
kono
parents:
diff changeset
1155 characters, we may also colorize the associated characters
kono
parents:
diff changeset
1156 within the source line.
kono
parents:
diff changeset
1157
kono
parents:
diff changeset
1158 For frontends that generate range information, we color the
kono
parents:
diff changeset
1159 associated characters in the source line the same as the
kono
parents:
diff changeset
1160 carets and underlines in the annotation line, to make it easier
kono
parents:
diff changeset
1161 for the reader to see the pertinent code.
kono
parents:
diff changeset
1162
kono
parents:
diff changeset
1163 For frontends that only generate carets, we don't colorize the
kono
parents:
diff changeset
1164 characters above them, since this would look strange (e.g.
kono
parents:
diff changeset
1165 colorizing just the first character in a token). */
kono
parents:
diff changeset
1166 if (m_colorize_source_p)
kono
parents:
diff changeset
1167 {
kono
parents:
diff changeset
1168 bool in_range_p;
kono
parents:
diff changeset
1169 point_state state;
kono
parents:
diff changeset
1170 in_range_p = get_state_at_point (row, column,
kono
parents:
diff changeset
1171 0, INT_MAX,
kono
parents:
diff changeset
1172 &state);
kono
parents:
diff changeset
1173 if (in_range_p)
kono
parents:
diff changeset
1174 m_colorizer.set_range (state.range_idx);
kono
parents:
diff changeset
1175 else
kono
parents:
diff changeset
1176 m_colorizer.set_normal_text ();
kono
parents:
diff changeset
1177 }
kono
parents:
diff changeset
1178 char c = *line == '\t' ? ' ' : *line;
kono
parents:
diff changeset
1179 if (c == '\0')
kono
parents:
diff changeset
1180 c = ' ';
kono
parents:
diff changeset
1181 if (c != ' ')
kono
parents:
diff changeset
1182 {
kono
parents:
diff changeset
1183 last_non_ws = column;
kono
parents:
diff changeset
1184 if (first_non_ws == INT_MAX)
kono
parents:
diff changeset
1185 first_non_ws = column;
kono
parents:
diff changeset
1186 }
kono
parents:
diff changeset
1187 pp_character (m_pp, c);
kono
parents:
diff changeset
1188 line++;
kono
parents:
diff changeset
1189 }
kono
parents:
diff changeset
1190 print_newline ();
kono
parents:
diff changeset
1191
kono
parents:
diff changeset
1192 lbounds_out->m_first_non_ws = first_non_ws;
kono
parents:
diff changeset
1193 lbounds_out->m_last_non_ws = last_non_ws;
kono
parents:
diff changeset
1194 }
kono
parents:
diff changeset
1195
kono
parents:
diff changeset
1196 /* Determine if we should print an annotation line for ROW.
kono
parents:
diff changeset
1197 i.e. if any of m_layout_ranges contains ROW. */
kono
parents:
diff changeset
1198
kono
parents:
diff changeset
1199 bool
kono
parents:
diff changeset
1200 layout::should_print_annotation_line_p (int row) const
kono
parents:
diff changeset
1201 {
kono
parents:
diff changeset
1202 layout_range *range;
kono
parents:
diff changeset
1203 int i;
kono
parents:
diff changeset
1204 FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
kono
parents:
diff changeset
1205 if (range->intersects_line_p (row))
kono
parents:
diff changeset
1206 return true;
kono
parents:
diff changeset
1207 return false;
kono
parents:
diff changeset
1208 }
kono
parents:
diff changeset
1209
kono
parents:
diff changeset
1210 /* Print a line consisting of the caret/underlines for the given
kono
parents:
diff changeset
1211 source line. */
kono
parents:
diff changeset
1212
kono
parents:
diff changeset
1213 void
kono
parents:
diff changeset
1214 layout::print_annotation_line (int row, const line_bounds lbounds)
kono
parents:
diff changeset
1215 {
kono
parents:
diff changeset
1216 int x_bound = get_x_bound_for_row (row, m_exploc.column,
kono
parents:
diff changeset
1217 lbounds.m_last_non_ws);
kono
parents:
diff changeset
1218
kono
parents:
diff changeset
1219 pp_space (m_pp);
kono
parents:
diff changeset
1220 for (int column = 1 + m_x_offset; column < x_bound; column++)
kono
parents:
diff changeset
1221 {
kono
parents:
diff changeset
1222 bool in_range_p;
kono
parents:
diff changeset
1223 point_state state;
kono
parents:
diff changeset
1224 in_range_p = get_state_at_point (row, column,
kono
parents:
diff changeset
1225 lbounds.m_first_non_ws,
kono
parents:
diff changeset
1226 lbounds.m_last_non_ws,
kono
parents:
diff changeset
1227 &state);
kono
parents:
diff changeset
1228 if (in_range_p)
kono
parents:
diff changeset
1229 {
kono
parents:
diff changeset
1230 /* Within a range. Draw either the caret or an underline. */
kono
parents:
diff changeset
1231 m_colorizer.set_range (state.range_idx);
kono
parents:
diff changeset
1232 if (state.draw_caret_p)
kono
parents:
diff changeset
1233 {
kono
parents:
diff changeset
1234 /* Draw the caret. */
kono
parents:
diff changeset
1235 char caret_char;
kono
parents:
diff changeset
1236 if (state.range_idx < rich_location::STATICALLY_ALLOCATED_RANGES)
kono
parents:
diff changeset
1237 caret_char = m_context->caret_chars[state.range_idx];
kono
parents:
diff changeset
1238 else
kono
parents:
diff changeset
1239 caret_char = '^';
kono
parents:
diff changeset
1240 pp_character (m_pp, caret_char);
kono
parents:
diff changeset
1241 }
kono
parents:
diff changeset
1242 else
kono
parents:
diff changeset
1243 pp_character (m_pp, '~');
kono
parents:
diff changeset
1244 }
kono
parents:
diff changeset
1245 else
kono
parents:
diff changeset
1246 {
kono
parents:
diff changeset
1247 /* Not in a range. */
kono
parents:
diff changeset
1248 m_colorizer.set_normal_text ();
kono
parents:
diff changeset
1249 pp_character (m_pp, ' ');
kono
parents:
diff changeset
1250 }
kono
parents:
diff changeset
1251 }
kono
parents:
diff changeset
1252 print_newline ();
kono
parents:
diff changeset
1253 }
kono
parents:
diff changeset
1254
kono
parents:
diff changeset
1255 /* If there are any fixit hints inserting new lines before source line ROW,
kono
parents:
diff changeset
1256 print them.
kono
parents:
diff changeset
1257
kono
parents:
diff changeset
1258 They are printed on lines of their own, before the source line
kono
parents:
diff changeset
1259 itself, with a leading '+'. */
kono
parents:
diff changeset
1260
kono
parents:
diff changeset
1261 void
kono
parents:
diff changeset
1262 layout::print_leading_fixits (int row)
kono
parents:
diff changeset
1263 {
kono
parents:
diff changeset
1264 for (unsigned int i = 0; i < m_fixit_hints.length (); i++)
kono
parents:
diff changeset
1265 {
kono
parents:
diff changeset
1266 const fixit_hint *hint = m_fixit_hints[i];
kono
parents:
diff changeset
1267
kono
parents:
diff changeset
1268 if (!hint->ends_with_newline_p ())
kono
parents:
diff changeset
1269 /* Not a newline fixit; print it in print_trailing_fixits. */
kono
parents:
diff changeset
1270 continue;
kono
parents:
diff changeset
1271
kono
parents:
diff changeset
1272 gcc_assert (hint->insertion_p ());
kono
parents:
diff changeset
1273
kono
parents:
diff changeset
1274 if (hint->affects_line_p (m_exploc.file, row))
kono
parents:
diff changeset
1275 {
kono
parents:
diff changeset
1276 /* Printing the '+' with normal colorization
kono
parents:
diff changeset
1277 and the inserted line with "insert" colorization
kono
parents:
diff changeset
1278 helps them stand out from each other, and from
kono
parents:
diff changeset
1279 the surrounding text. */
kono
parents:
diff changeset
1280 m_colorizer.set_normal_text ();
kono
parents:
diff changeset
1281 pp_character (m_pp, '+');
kono
parents:
diff changeset
1282 m_colorizer.set_fixit_insert ();
kono
parents:
diff changeset
1283 /* Print all but the trailing newline of the fix-it hint.
kono
parents:
diff changeset
1284 We have to print the newline separately to avoid
kono
parents:
diff changeset
1285 getting additional pp prefixes printed. */
kono
parents:
diff changeset
1286 for (size_t i = 0; i < hint->get_length () - 1; i++)
kono
parents:
diff changeset
1287 pp_character (m_pp, hint->get_string ()[i]);
kono
parents:
diff changeset
1288 m_colorizer.set_normal_text ();
kono
parents:
diff changeset
1289 pp_newline (m_pp);
kono
parents:
diff changeset
1290 }
kono
parents:
diff changeset
1291 }
kono
parents:
diff changeset
1292 }
kono
parents:
diff changeset
1293
kono
parents:
diff changeset
1294 /* Subroutine of layout::print_trailing_fixits.
kono
parents:
diff changeset
1295
kono
parents:
diff changeset
1296 Determine if the annotation line printed for LINE contained
kono
parents:
diff changeset
1297 the exact range from START_COLUMN to FINISH_COLUMN. */
kono
parents:
diff changeset
1298
kono
parents:
diff changeset
1299 bool
kono
parents:
diff changeset
1300 layout::annotation_line_showed_range_p (int line, int start_column,
kono
parents:
diff changeset
1301 int finish_column) const
kono
parents:
diff changeset
1302 {
kono
parents:
diff changeset
1303 layout_range *range;
kono
parents:
diff changeset
1304 int i;
kono
parents:
diff changeset
1305 FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
kono
parents:
diff changeset
1306 if (range->m_start.m_line == line
kono
parents:
diff changeset
1307 && range->m_start.m_column == start_column
kono
parents:
diff changeset
1308 && range->m_finish.m_line == line
kono
parents:
diff changeset
1309 && range->m_finish.m_column == finish_column)
kono
parents:
diff changeset
1310 return true;
kono
parents:
diff changeset
1311 return false;
kono
parents:
diff changeset
1312 }
kono
parents:
diff changeset
1313
kono
parents:
diff changeset
1314 /* Classes for printing trailing fix-it hints i.e. those that
kono
parents:
diff changeset
1315 don't add new lines.
kono
parents:
diff changeset
1316
kono
parents:
diff changeset
1317 For insertion, these can look like:
kono
parents:
diff changeset
1318
kono
parents:
diff changeset
1319 new_text
kono
parents:
diff changeset
1320
kono
parents:
diff changeset
1321 For replacement, these can look like:
kono
parents:
diff changeset
1322
kono
parents:
diff changeset
1323 ------------- : underline showing affected range
kono
parents:
diff changeset
1324 new_text
kono
parents:
diff changeset
1325
kono
parents:
diff changeset
1326 For deletion, these can look like:
kono
parents:
diff changeset
1327
kono
parents:
diff changeset
1328 ------------- : underline showing affected range
kono
parents:
diff changeset
1329
kono
parents:
diff changeset
1330 This can become confusing if they overlap, and so we need
kono
parents:
diff changeset
1331 to do some preprocessing to decide what to print.
kono
parents:
diff changeset
1332 We use the list of fixit_hint instances affecting the line
kono
parents:
diff changeset
1333 to build a list of "correction" instances, and print the
kono
parents:
diff changeset
1334 latter.
kono
parents:
diff changeset
1335
kono
parents:
diff changeset
1336 For example, consider a set of fix-its for converting
kono
parents:
diff changeset
1337 a C-style cast to a C++ const_cast.
kono
parents:
diff changeset
1338
kono
parents:
diff changeset
1339 Given:
kono
parents:
diff changeset
1340
kono
parents:
diff changeset
1341 ..000000000111111111122222222223333333333.
kono
parents:
diff changeset
1342 ..123456789012345678901234567890123456789.
kono
parents:
diff changeset
1343 foo *f = (foo *)ptr->field;
kono
parents:
diff changeset
1344 ^~~~~
kono
parents:
diff changeset
1345
kono
parents:
diff changeset
1346 and the fix-it hints:
kono
parents:
diff changeset
1347 - replace col 10 (the open paren) with "const_cast<"
kono
parents:
diff changeset
1348 - replace col 16 (the close paren) with "> ("
kono
parents:
diff changeset
1349 - insert ")" before col 27
kono
parents:
diff changeset
1350
kono
parents:
diff changeset
1351 then we would get odd-looking output:
kono
parents:
diff changeset
1352
kono
parents:
diff changeset
1353 foo *f = (foo *)ptr->field;
kono
parents:
diff changeset
1354 ^~~~~
kono
parents:
diff changeset
1355 -
kono
parents:
diff changeset
1356 const_cast<
kono
parents:
diff changeset
1357 -
kono
parents:
diff changeset
1358 > ( )
kono
parents:
diff changeset
1359
kono
parents:
diff changeset
1360 It would be better to detect when fixit hints are going to
kono
parents:
diff changeset
1361 overlap (those that require new lines), and to consolidate
kono
parents:
diff changeset
1362 the printing of such fixits, giving something like:
kono
parents:
diff changeset
1363
kono
parents:
diff changeset
1364 foo *f = (foo *)ptr->field;
kono
parents:
diff changeset
1365 ^~~~~
kono
parents:
diff changeset
1366 -----------------
kono
parents:
diff changeset
1367 const_cast<foo *> (ptr->field)
kono
parents:
diff changeset
1368
kono
parents:
diff changeset
1369 This works by detecting when the printing would overlap, and
kono
parents:
diff changeset
1370 effectively injecting no-op replace hints into the gaps between
kono
parents:
diff changeset
1371 such fix-its, so that the printing joins up.
kono
parents:
diff changeset
1372
kono
parents:
diff changeset
1373 In the above example, the overlap of:
kono
parents:
diff changeset
1374 - replace col 10 (the open paren) with "const_cast<"
kono
parents:
diff changeset
1375 and:
kono
parents:
diff changeset
1376 - replace col 16 (the close paren) with "> ("
kono
parents:
diff changeset
1377 is fixed by injecting a no-op:
kono
parents:
diff changeset
1378 - replace cols 11-15 with themselves ("foo *")
kono
parents:
diff changeset
1379 and consolidating these, making:
kono
parents:
diff changeset
1380 - replace cols 10-16 with "const_cast<" + "foo *" + "> ("
kono
parents:
diff changeset
1381 i.e.:
kono
parents:
diff changeset
1382 - replace cols 10-16 with "const_cast<foo *> ("
kono
parents:
diff changeset
1383
kono
parents:
diff changeset
1384 This overlaps with the final fix-it hint:
kono
parents:
diff changeset
1385 - insert ")" before col 27
kono
parents:
diff changeset
1386 and so we repeat the consolidation process, by injecting
kono
parents:
diff changeset
1387 a no-op:
kono
parents:
diff changeset
1388 - replace cols 17-26 with themselves ("ptr->field")
kono
parents:
diff changeset
1389 giving:
kono
parents:
diff changeset
1390 - replace cols 10-26 with "const_cast<foo *> (" + "ptr->field" + ")"
kono
parents:
diff changeset
1391 i.e.:
kono
parents:
diff changeset
1392 - replace cols 10-26 with "const_cast<foo *> (ptr->field)"
kono
parents:
diff changeset
1393
kono
parents:
diff changeset
1394 and is thus printed as desired. */
kono
parents:
diff changeset
1395
kono
parents:
diff changeset
1396 /* A range of columns within a line. */
kono
parents:
diff changeset
1397
kono
parents:
diff changeset
1398 struct column_range
kono
parents:
diff changeset
1399 {
kono
parents:
diff changeset
1400 column_range (int start_, int finish_) : start (start_), finish (finish_)
kono
parents:
diff changeset
1401 {
kono
parents:
diff changeset
1402 /* We must have either a range, or an insertion. */
kono
parents:
diff changeset
1403 gcc_assert (start <= finish || finish == start - 1);
kono
parents:
diff changeset
1404 }
kono
parents:
diff changeset
1405
kono
parents:
diff changeset
1406 bool operator== (const column_range &other) const
kono
parents:
diff changeset
1407 {
kono
parents:
diff changeset
1408 return start == other.start && finish == other.finish;
kono
parents:
diff changeset
1409 }
kono
parents:
diff changeset
1410
kono
parents:
diff changeset
1411 int start;
kono
parents:
diff changeset
1412 int finish;
kono
parents:
diff changeset
1413 };
kono
parents:
diff changeset
1414
kono
parents:
diff changeset
1415 /* Get the range of columns that HINT would affect. */
kono
parents:
diff changeset
1416
kono
parents:
diff changeset
1417 static column_range
kono
parents:
diff changeset
1418 get_affected_columns (const fixit_hint *hint)
kono
parents:
diff changeset
1419 {
kono
parents:
diff changeset
1420 int start_column = LOCATION_COLUMN (hint->get_start_loc ());
kono
parents:
diff changeset
1421 int finish_column = LOCATION_COLUMN (hint->get_next_loc ()) - 1;
kono
parents:
diff changeset
1422
kono
parents:
diff changeset
1423 return column_range (start_column, finish_column);
kono
parents:
diff changeset
1424 }
kono
parents:
diff changeset
1425
kono
parents:
diff changeset
1426 /* Get the range of columns that would be printed for HINT. */
kono
parents:
diff changeset
1427
kono
parents:
diff changeset
1428 static column_range
kono
parents:
diff changeset
1429 get_printed_columns (const fixit_hint *hint)
kono
parents:
diff changeset
1430 {
kono
parents:
diff changeset
1431 int start_column = LOCATION_COLUMN (hint->get_start_loc ());
kono
parents:
diff changeset
1432 int final_hint_column = start_column + hint->get_length () - 1;
kono
parents:
diff changeset
1433 if (hint->insertion_p ())
kono
parents:
diff changeset
1434 {
kono
parents:
diff changeset
1435 return column_range (start_column, final_hint_column);
kono
parents:
diff changeset
1436 }
kono
parents:
diff changeset
1437 else
kono
parents:
diff changeset
1438 {
kono
parents:
diff changeset
1439 int finish_column = LOCATION_COLUMN (hint->get_next_loc ()) - 1;
kono
parents:
diff changeset
1440
kono
parents:
diff changeset
1441 return column_range (start_column,
kono
parents:
diff changeset
1442 MAX (finish_column, final_hint_column));
kono
parents:
diff changeset
1443 }
kono
parents:
diff changeset
1444 }
kono
parents:
diff changeset
1445
kono
parents:
diff changeset
1446 /* A struct capturing the bounds of a buffer, to allow for run-time
kono
parents:
diff changeset
1447 bounds-checking in a checked build. */
kono
parents:
diff changeset
1448
kono
parents:
diff changeset
1449 struct char_span
kono
parents:
diff changeset
1450 {
kono
parents:
diff changeset
1451 char_span (const char *ptr, size_t n_elts) : m_ptr (ptr), m_n_elts (n_elts) {}
kono
parents:
diff changeset
1452
kono
parents:
diff changeset
1453 char_span subspan (int offset, int n_elts)
kono
parents:
diff changeset
1454 {
kono
parents:
diff changeset
1455 gcc_assert (offset >= 0);
kono
parents:
diff changeset
1456 gcc_assert (offset < (int)m_n_elts);
kono
parents:
diff changeset
1457 gcc_assert (n_elts >= 0);
kono
parents:
diff changeset
1458 gcc_assert (offset + n_elts <= (int)m_n_elts);
kono
parents:
diff changeset
1459 return char_span (m_ptr + offset, n_elts);
kono
parents:
diff changeset
1460 }
kono
parents:
diff changeset
1461
kono
parents:
diff changeset
1462 const char *m_ptr;
kono
parents:
diff changeset
1463 size_t m_n_elts;
kono
parents:
diff changeset
1464 };
kono
parents:
diff changeset
1465
kono
parents:
diff changeset
1466 /* A correction on a particular line.
kono
parents:
diff changeset
1467 This describes a plan for how to print one or more fixit_hint
kono
parents:
diff changeset
1468 instances that affected the line, potentially consolidating hints
kono
parents:
diff changeset
1469 into corrections to make the result easier for the user to read. */
kono
parents:
diff changeset
1470
kono
parents:
diff changeset
1471 struct correction
kono
parents:
diff changeset
1472 {
kono
parents:
diff changeset
1473 correction (column_range affected_columns,
kono
parents:
diff changeset
1474 column_range printed_columns,
kono
parents:
diff changeset
1475 const char *new_text, size_t new_text_len)
kono
parents:
diff changeset
1476 : m_affected_columns (affected_columns),
kono
parents:
diff changeset
1477 m_printed_columns (printed_columns),
kono
parents:
diff changeset
1478 m_text (xstrdup (new_text)),
kono
parents:
diff changeset
1479 m_len (new_text_len),
kono
parents:
diff changeset
1480 m_alloc_sz (new_text_len + 1)
kono
parents:
diff changeset
1481 {
kono
parents:
diff changeset
1482 }
kono
parents:
diff changeset
1483
kono
parents:
diff changeset
1484 ~correction () { free (m_text); }
kono
parents:
diff changeset
1485
kono
parents:
diff changeset
1486 bool insertion_p () const
kono
parents:
diff changeset
1487 {
kono
parents:
diff changeset
1488 return m_affected_columns.start == m_affected_columns.finish + 1;
kono
parents:
diff changeset
1489 }
kono
parents:
diff changeset
1490
kono
parents:
diff changeset
1491 void ensure_capacity (size_t len);
kono
parents:
diff changeset
1492 void ensure_terminated ();
kono
parents:
diff changeset
1493
kono
parents:
diff changeset
1494 void overwrite (int dst_offset, const char_span &src_span)
kono
parents:
diff changeset
1495 {
kono
parents:
diff changeset
1496 gcc_assert (dst_offset >= 0);
kono
parents:
diff changeset
1497 gcc_assert (dst_offset + src_span.m_n_elts < m_alloc_sz);
kono
parents:
diff changeset
1498 memcpy (m_text + dst_offset, src_span.m_ptr,
kono
parents:
diff changeset
1499 src_span.m_n_elts);
kono
parents:
diff changeset
1500 }
kono
parents:
diff changeset
1501
kono
parents:
diff changeset
1502 /* If insert, then start: the column before which the text
kono
parents:
diff changeset
1503 is to be inserted, and finish is offset by the length of
kono
parents:
diff changeset
1504 the replacement.
kono
parents:
diff changeset
1505 If replace, then the range of columns affected. */
kono
parents:
diff changeset
1506 column_range m_affected_columns;
kono
parents:
diff changeset
1507
kono
parents:
diff changeset
1508 /* If insert, then start: the column before which the text
kono
parents:
diff changeset
1509 is to be inserted, and finish is offset by the length of
kono
parents:
diff changeset
1510 the replacement.
kono
parents:
diff changeset
1511 If replace, then the range of columns affected. */
kono
parents:
diff changeset
1512 column_range m_printed_columns;
kono
parents:
diff changeset
1513
kono
parents:
diff changeset
1514 /* The text to be inserted/used as replacement. */
kono
parents:
diff changeset
1515 char *m_text;
kono
parents:
diff changeset
1516 size_t m_len;
kono
parents:
diff changeset
1517 size_t m_alloc_sz;
kono
parents:
diff changeset
1518 };
kono
parents:
diff changeset
1519
kono
parents:
diff changeset
1520 /* Ensure that m_text can hold a string of length LEN
kono
parents:
diff changeset
1521 (plus 1 for 0-termination). */
kono
parents:
diff changeset
1522
kono
parents:
diff changeset
1523 void
kono
parents:
diff changeset
1524 correction::ensure_capacity (size_t len)
kono
parents:
diff changeset
1525 {
kono
parents:
diff changeset
1526 /* Allow 1 extra byte for 0-termination. */
kono
parents:
diff changeset
1527 if (m_alloc_sz < (len + 1))
kono
parents:
diff changeset
1528 {
kono
parents:
diff changeset
1529 size_t new_alloc_sz = (len + 1) * 2;
kono
parents:
diff changeset
1530 m_text = (char *)xrealloc (m_text, new_alloc_sz);
kono
parents:
diff changeset
1531 m_alloc_sz = new_alloc_sz;
kono
parents:
diff changeset
1532 }
kono
parents:
diff changeset
1533 }
kono
parents:
diff changeset
1534
kono
parents:
diff changeset
1535 /* Ensure that m_text is 0-terminated. */
kono
parents:
diff changeset
1536
kono
parents:
diff changeset
1537 void
kono
parents:
diff changeset
1538 correction::ensure_terminated ()
kono
parents:
diff changeset
1539 {
kono
parents:
diff changeset
1540 /* 0-terminate the buffer. */
kono
parents:
diff changeset
1541 gcc_assert (m_len < m_alloc_sz);
kono
parents:
diff changeset
1542 m_text[m_len] = '\0';
kono
parents:
diff changeset
1543 }
kono
parents:
diff changeset
1544
kono
parents:
diff changeset
1545 /* A list of corrections affecting a particular line.
kono
parents:
diff changeset
1546 This is used by layout::print_trailing_fixits for planning
kono
parents:
diff changeset
1547 how to print the fix-it hints affecting the line. */
kono
parents:
diff changeset
1548
kono
parents:
diff changeset
1549 struct line_corrections
kono
parents:
diff changeset
1550 {
kono
parents:
diff changeset
1551 line_corrections (const char *filename, int row)
kono
parents:
diff changeset
1552 : m_filename (filename), m_row (row)
kono
parents:
diff changeset
1553 {}
kono
parents:
diff changeset
1554 ~line_corrections ();
kono
parents:
diff changeset
1555
kono
parents:
diff changeset
1556 void add_hint (const fixit_hint *hint);
kono
parents:
diff changeset
1557
kono
parents:
diff changeset
1558 const char *m_filename;
kono
parents:
diff changeset
1559 int m_row;
kono
parents:
diff changeset
1560 auto_vec <correction *> m_corrections;
kono
parents:
diff changeset
1561 };
kono
parents:
diff changeset
1562
kono
parents:
diff changeset
1563 /* struct line_corrections. */
kono
parents:
diff changeset
1564
kono
parents:
diff changeset
1565 line_corrections::~line_corrections ()
kono
parents:
diff changeset
1566 {
kono
parents:
diff changeset
1567 unsigned i;
kono
parents:
diff changeset
1568 correction *c;
kono
parents:
diff changeset
1569 FOR_EACH_VEC_ELT (m_corrections, i, c)
kono
parents:
diff changeset
1570 delete c;
kono
parents:
diff changeset
1571 }
kono
parents:
diff changeset
1572
kono
parents:
diff changeset
1573 /* A struct wrapping a particular source line, allowing
kono
parents:
diff changeset
1574 run-time bounds-checking of accesses in a checked build. */
kono
parents:
diff changeset
1575
kono
parents:
diff changeset
1576 struct source_line
kono
parents:
diff changeset
1577 {
kono
parents:
diff changeset
1578 source_line (const char *filename, int line);
kono
parents:
diff changeset
1579
kono
parents:
diff changeset
1580 char_span as_span () { return char_span (chars, width); }
kono
parents:
diff changeset
1581
kono
parents:
diff changeset
1582 const char *chars;
kono
parents:
diff changeset
1583 int width;
kono
parents:
diff changeset
1584 };
kono
parents:
diff changeset
1585
kono
parents:
diff changeset
1586 /* source_line's ctor. */
kono
parents:
diff changeset
1587
kono
parents:
diff changeset
1588 source_line::source_line (const char *filename, int line)
kono
parents:
diff changeset
1589 {
kono
parents:
diff changeset
1590 chars = location_get_source_line (filename, line, &width);
kono
parents:
diff changeset
1591 }
kono
parents:
diff changeset
1592
kono
parents:
diff changeset
1593 /* Add HINT to the corrections for this line.
kono
parents:
diff changeset
1594 Attempt to consolidate nearby hints so that they will not
kono
parents:
diff changeset
1595 overlap with printed. */
kono
parents:
diff changeset
1596
kono
parents:
diff changeset
1597 void
kono
parents:
diff changeset
1598 line_corrections::add_hint (const fixit_hint *hint)
kono
parents:
diff changeset
1599 {
kono
parents:
diff changeset
1600 column_range affected_columns = get_affected_columns (hint);
kono
parents:
diff changeset
1601 column_range printed_columns = get_printed_columns (hint);
kono
parents:
diff changeset
1602
kono
parents:
diff changeset
1603 /* Potentially consolidate. */
kono
parents:
diff changeset
1604 if (!m_corrections.is_empty ())
kono
parents:
diff changeset
1605 {
kono
parents:
diff changeset
1606 correction *last_correction
kono
parents:
diff changeset
1607 = m_corrections[m_corrections.length () - 1];
kono
parents:
diff changeset
1608
kono
parents:
diff changeset
1609 /* The following consolidation code assumes that the fix-it hints
kono
parents:
diff changeset
1610 have been sorted by start (done within layout's ctor). */
kono
parents:
diff changeset
1611 gcc_assert (affected_columns.start
kono
parents:
diff changeset
1612 >= last_correction->m_affected_columns.start);
kono
parents:
diff changeset
1613 gcc_assert (printed_columns.start
kono
parents:
diff changeset
1614 >= last_correction->m_printed_columns.start);
kono
parents:
diff changeset
1615
kono
parents:
diff changeset
1616 if (printed_columns.start <= last_correction->m_printed_columns.finish)
kono
parents:
diff changeset
1617 {
kono
parents:
diff changeset
1618 /* We have two hints for which the printed forms of the hints
kono
parents:
diff changeset
1619 would touch or overlap, so we need to consolidate them to avoid
kono
parents:
diff changeset
1620 confusing the user.
kono
parents:
diff changeset
1621 Attempt to inject a "replace" correction from immediately
kono
parents:
diff changeset
1622 after the end of the last hint to immediately before the start
kono
parents:
diff changeset
1623 of the next hint. */
kono
parents:
diff changeset
1624 column_range between (last_correction->m_affected_columns.finish + 1,
kono
parents:
diff changeset
1625 printed_columns.start - 1);
kono
parents:
diff changeset
1626
kono
parents:
diff changeset
1627 /* Try to read the source. */
kono
parents:
diff changeset
1628 source_line line (m_filename, m_row);
kono
parents:
diff changeset
1629 if (line.chars && between.finish < line.width)
kono
parents:
diff changeset
1630 {
kono
parents:
diff changeset
1631 /* Consolidate into the last correction:
kono
parents:
diff changeset
1632 add a no-op "replace" of the "between" text, and
kono
parents:
diff changeset
1633 add the text from the new hint. */
kono
parents:
diff changeset
1634 int old_len = last_correction->m_len;
kono
parents:
diff changeset
1635 gcc_assert (old_len >= 0);
kono
parents:
diff changeset
1636 int between_len = between.finish + 1 - between.start;
kono
parents:
diff changeset
1637 gcc_assert (between_len >= 0);
kono
parents:
diff changeset
1638 int new_len = old_len + between_len + hint->get_length ();
kono
parents:
diff changeset
1639 gcc_assert (new_len >= 0);
kono
parents:
diff changeset
1640 last_correction->ensure_capacity (new_len);
kono
parents:
diff changeset
1641 last_correction->overwrite
kono
parents:
diff changeset
1642 (old_len,
kono
parents:
diff changeset
1643 line.as_span ().subspan (between.start - 1,
kono
parents:
diff changeset
1644 between.finish + 1 - between.start));
kono
parents:
diff changeset
1645 last_correction->overwrite (old_len + between_len,
kono
parents:
diff changeset
1646 char_span (hint->get_string (),
kono
parents:
diff changeset
1647 hint->get_length ()));
kono
parents:
diff changeset
1648 last_correction->m_len = new_len;
kono
parents:
diff changeset
1649 last_correction->ensure_terminated ();
kono
parents:
diff changeset
1650 last_correction->m_affected_columns.finish
kono
parents:
diff changeset
1651 = affected_columns.finish;
kono
parents:
diff changeset
1652 last_correction->m_printed_columns.finish
kono
parents:
diff changeset
1653 += between_len + hint->get_length ();
kono
parents:
diff changeset
1654 return;
kono
parents:
diff changeset
1655 }
kono
parents:
diff changeset
1656 }
kono
parents:
diff changeset
1657 }
kono
parents:
diff changeset
1658
kono
parents:
diff changeset
1659 /* If no consolidation happened, add a new correction instance. */
kono
parents:
diff changeset
1660 m_corrections.safe_push (new correction (affected_columns,
kono
parents:
diff changeset
1661 printed_columns,
kono
parents:
diff changeset
1662 hint->get_string (),
kono
parents:
diff changeset
1663 hint->get_length ()));
kono
parents:
diff changeset
1664 }
kono
parents:
diff changeset
1665
kono
parents:
diff changeset
1666 /* If there are any fixit hints on source line ROW, print them.
kono
parents:
diff changeset
1667 They are printed in order, attempting to combine them onto lines, but
kono
parents:
diff changeset
1668 starting new lines if necessary.
kono
parents:
diff changeset
1669 Fix-it hints that insert new lines are handled separately,
kono
parents:
diff changeset
1670 in layout::print_leading_fixits. */
kono
parents:
diff changeset
1671
kono
parents:
diff changeset
1672 void
kono
parents:
diff changeset
1673 layout::print_trailing_fixits (int row)
kono
parents:
diff changeset
1674 {
kono
parents:
diff changeset
1675 /* Build a list of correction instances for the line,
kono
parents:
diff changeset
1676 potentially consolidating hints (for the sake of readability). */
kono
parents:
diff changeset
1677 line_corrections corrections (m_exploc.file, row);
kono
parents:
diff changeset
1678 for (unsigned int i = 0; i < m_fixit_hints.length (); i++)
kono
parents:
diff changeset
1679 {
kono
parents:
diff changeset
1680 const fixit_hint *hint = m_fixit_hints[i];
kono
parents:
diff changeset
1681
kono
parents:
diff changeset
1682 /* Newline fixits are handled by layout::print_leading_fixits. */
kono
parents:
diff changeset
1683 if (hint->ends_with_newline_p ())
kono
parents:
diff changeset
1684 continue;
kono
parents:
diff changeset
1685
kono
parents:
diff changeset
1686 if (hint->affects_line_p (m_exploc.file, row))
kono
parents:
diff changeset
1687 corrections.add_hint (hint);
kono
parents:
diff changeset
1688 }
kono
parents:
diff changeset
1689
kono
parents:
diff changeset
1690 /* Now print the corrections. */
kono
parents:
diff changeset
1691 unsigned i;
kono
parents:
diff changeset
1692 correction *c;
kono
parents:
diff changeset
1693 int column = 0;
kono
parents:
diff changeset
1694
kono
parents:
diff changeset
1695 FOR_EACH_VEC_ELT (corrections.m_corrections, i, c)
kono
parents:
diff changeset
1696 {
kono
parents:
diff changeset
1697 /* For now we assume each fixit hint can only touch one line. */
kono
parents:
diff changeset
1698 if (c->insertion_p ())
kono
parents:
diff changeset
1699 {
kono
parents:
diff changeset
1700 /* This assumes the insertion just affects one line. */
kono
parents:
diff changeset
1701 int start_column = c->m_printed_columns.start;
kono
parents:
diff changeset
1702 move_to_column (&column, start_column);
kono
parents:
diff changeset
1703 m_colorizer.set_fixit_insert ();
kono
parents:
diff changeset
1704 pp_string (m_pp, c->m_text);
kono
parents:
diff changeset
1705 m_colorizer.set_normal_text ();
kono
parents:
diff changeset
1706 column += c->m_len;
kono
parents:
diff changeset
1707 }
kono
parents:
diff changeset
1708 else
kono
parents:
diff changeset
1709 {
kono
parents:
diff changeset
1710 /* If the range of the replacement wasn't printed in the
kono
parents:
diff changeset
1711 annotation line, then print an extra underline to
kono
parents:
diff changeset
1712 indicate exactly what is being replaced.
kono
parents:
diff changeset
1713 Always show it for removals. */
kono
parents:
diff changeset
1714 int start_column = c->m_affected_columns.start;
kono
parents:
diff changeset
1715 int finish_column = c->m_affected_columns.finish;
kono
parents:
diff changeset
1716 if (!annotation_line_showed_range_p (row, start_column,
kono
parents:
diff changeset
1717 finish_column)
kono
parents:
diff changeset
1718 || c->m_len == 0)
kono
parents:
diff changeset
1719 {
kono
parents:
diff changeset
1720 move_to_column (&column, start_column);
kono
parents:
diff changeset
1721 m_colorizer.set_fixit_delete ();
kono
parents:
diff changeset
1722 for (; column <= finish_column; column++)
kono
parents:
diff changeset
1723 pp_character (m_pp, '-');
kono
parents:
diff changeset
1724 m_colorizer.set_normal_text ();
kono
parents:
diff changeset
1725 }
kono
parents:
diff changeset
1726 /* Print the replacement text. REPLACE also covers
kono
parents:
diff changeset
1727 removals, so only do this extra work (potentially starting
kono
parents:
diff changeset
1728 a new line) if we have actual replacement text. */
kono
parents:
diff changeset
1729 if (c->m_len > 0)
kono
parents:
diff changeset
1730 {
kono
parents:
diff changeset
1731 move_to_column (&column, start_column);
kono
parents:
diff changeset
1732 m_colorizer.set_fixit_insert ();
kono
parents:
diff changeset
1733 pp_string (m_pp, c->m_text);
kono
parents:
diff changeset
1734 m_colorizer.set_normal_text ();
kono
parents:
diff changeset
1735 column += c->m_len;
kono
parents:
diff changeset
1736 }
kono
parents:
diff changeset
1737 }
kono
parents:
diff changeset
1738 }
kono
parents:
diff changeset
1739
kono
parents:
diff changeset
1740 /* Add a trailing newline, if necessary. */
kono
parents:
diff changeset
1741 move_to_column (&column, 0);
kono
parents:
diff changeset
1742 }
kono
parents:
diff changeset
1743
kono
parents:
diff changeset
1744 /* Disable any colorization and emit a newline. */
kono
parents:
diff changeset
1745
kono
parents:
diff changeset
1746 void
kono
parents:
diff changeset
1747 layout::print_newline ()
kono
parents:
diff changeset
1748 {
kono
parents:
diff changeset
1749 m_colorizer.set_normal_text ();
kono
parents:
diff changeset
1750 pp_newline (m_pp);
kono
parents:
diff changeset
1751 }
kono
parents:
diff changeset
1752
kono
parents:
diff changeset
1753 /* Return true if (ROW/COLUMN) is within a range of the layout.
kono
parents:
diff changeset
1754 If it returns true, OUT_STATE is written to, with the
kono
parents:
diff changeset
1755 range index, and whether we should draw the caret at
kono
parents:
diff changeset
1756 (ROW/COLUMN) (as opposed to an underline). */
kono
parents:
diff changeset
1757
kono
parents:
diff changeset
1758 bool
kono
parents:
diff changeset
1759 layout::get_state_at_point (/* Inputs. */
kono
parents:
diff changeset
1760 int row, int column,
kono
parents:
diff changeset
1761 int first_non_ws, int last_non_ws,
kono
parents:
diff changeset
1762 /* Outputs. */
kono
parents:
diff changeset
1763 point_state *out_state)
kono
parents:
diff changeset
1764 {
kono
parents:
diff changeset
1765 layout_range *range;
kono
parents:
diff changeset
1766 int i;
kono
parents:
diff changeset
1767 FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
kono
parents:
diff changeset
1768 {
kono
parents:
diff changeset
1769 if (range->contains_point (row, column))
kono
parents:
diff changeset
1770 {
kono
parents:
diff changeset
1771 out_state->range_idx = i;
kono
parents:
diff changeset
1772
kono
parents:
diff changeset
1773 /* Are we at the range's caret? is it visible? */
kono
parents:
diff changeset
1774 out_state->draw_caret_p = false;
kono
parents:
diff changeset
1775 if (range->m_show_caret_p
kono
parents:
diff changeset
1776 && row == range->m_caret.m_line
kono
parents:
diff changeset
1777 && column == range->m_caret.m_column)
kono
parents:
diff changeset
1778 out_state->draw_caret_p = true;
kono
parents:
diff changeset
1779
kono
parents:
diff changeset
1780 /* Within a multiline range, don't display any underline
kono
parents:
diff changeset
1781 in any leading or trailing whitespace on a line.
kono
parents:
diff changeset
1782 We do display carets, however. */
kono
parents:
diff changeset
1783 if (!out_state->draw_caret_p)
kono
parents:
diff changeset
1784 if (column < first_non_ws || column > last_non_ws)
kono
parents:
diff changeset
1785 return false;
kono
parents:
diff changeset
1786
kono
parents:
diff changeset
1787 /* We are within a range. */
kono
parents:
diff changeset
1788 return true;
kono
parents:
diff changeset
1789 }
kono
parents:
diff changeset
1790 }
kono
parents:
diff changeset
1791
kono
parents:
diff changeset
1792 return false;
kono
parents:
diff changeset
1793 }
kono
parents:
diff changeset
1794
kono
parents:
diff changeset
1795 /* Helper function for use by layout::print_line when printing the
kono
parents:
diff changeset
1796 annotation line under the source line.
kono
parents:
diff changeset
1797 Get the column beyond the rightmost one that could contain a caret or
kono
parents:
diff changeset
1798 range marker, given that we stop rendering at trailing whitespace.
kono
parents:
diff changeset
1799 ROW is the source line within the given file.
kono
parents:
diff changeset
1800 CARET_COLUMN is the column of range 0's caret.
kono
parents:
diff changeset
1801 LAST_NON_WS_COLUMN is the last column containing a non-whitespace
kono
parents:
diff changeset
1802 character of source (as determined when printing the source line). */
kono
parents:
diff changeset
1803
kono
parents:
diff changeset
1804 int
kono
parents:
diff changeset
1805 layout::get_x_bound_for_row (int row, int caret_column,
kono
parents:
diff changeset
1806 int last_non_ws_column)
kono
parents:
diff changeset
1807 {
kono
parents:
diff changeset
1808 int result = caret_column + 1;
kono
parents:
diff changeset
1809
kono
parents:
diff changeset
1810 layout_range *range;
kono
parents:
diff changeset
1811 int i;
kono
parents:
diff changeset
1812 FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
kono
parents:
diff changeset
1813 {
kono
parents:
diff changeset
1814 if (row >= range->m_start.m_line)
kono
parents:
diff changeset
1815 {
kono
parents:
diff changeset
1816 if (range->m_finish.m_line == row)
kono
parents:
diff changeset
1817 {
kono
parents:
diff changeset
1818 /* On the final line within a range; ensure that
kono
parents:
diff changeset
1819 we render up to the end of the range. */
kono
parents:
diff changeset
1820 if (result <= range->m_finish.m_column)
kono
parents:
diff changeset
1821 result = range->m_finish.m_column + 1;
kono
parents:
diff changeset
1822 }
kono
parents:
diff changeset
1823 else if (row < range->m_finish.m_line)
kono
parents:
diff changeset
1824 {
kono
parents:
diff changeset
1825 /* Within a multiline range; ensure that we render up to the
kono
parents:
diff changeset
1826 last non-whitespace column. */
kono
parents:
diff changeset
1827 if (result <= last_non_ws_column)
kono
parents:
diff changeset
1828 result = last_non_ws_column + 1;
kono
parents:
diff changeset
1829 }
kono
parents:
diff changeset
1830 }
kono
parents:
diff changeset
1831 }
kono
parents:
diff changeset
1832
kono
parents:
diff changeset
1833 return result;
kono
parents:
diff changeset
1834 }
kono
parents:
diff changeset
1835
kono
parents:
diff changeset
1836 /* Given *COLUMN as an x-coordinate, print spaces to position
kono
parents:
diff changeset
1837 successive output at DEST_COLUMN, printing a newline if necessary,
kono
parents:
diff changeset
1838 and updating *COLUMN. */
kono
parents:
diff changeset
1839
kono
parents:
diff changeset
1840 void
kono
parents:
diff changeset
1841 layout::move_to_column (int *column, int dest_column)
kono
parents:
diff changeset
1842 {
kono
parents:
diff changeset
1843 /* Start a new line if we need to. */
kono
parents:
diff changeset
1844 if (*column > dest_column)
kono
parents:
diff changeset
1845 {
kono
parents:
diff changeset
1846 print_newline ();
kono
parents:
diff changeset
1847 *column = 0;
kono
parents:
diff changeset
1848 }
kono
parents:
diff changeset
1849
kono
parents:
diff changeset
1850 while (*column < dest_column)
kono
parents:
diff changeset
1851 {
kono
parents:
diff changeset
1852 pp_space (m_pp);
kono
parents:
diff changeset
1853 (*column)++;
kono
parents:
diff changeset
1854 }
kono
parents:
diff changeset
1855 }
kono
parents:
diff changeset
1856
kono
parents:
diff changeset
1857 /* For debugging layout issues, render a ruler giving column numbers
kono
parents:
diff changeset
1858 (after the 1-column indent). */
kono
parents:
diff changeset
1859
kono
parents:
diff changeset
1860 void
kono
parents:
diff changeset
1861 layout::show_ruler (int max_column) const
kono
parents:
diff changeset
1862 {
kono
parents:
diff changeset
1863 /* Hundreds. */
kono
parents:
diff changeset
1864 if (max_column > 99)
kono
parents:
diff changeset
1865 {
kono
parents:
diff changeset
1866 pp_space (m_pp);
kono
parents:
diff changeset
1867 for (int column = 1 + m_x_offset; column <= max_column; column++)
kono
parents:
diff changeset
1868 if (0 == column % 10)
kono
parents:
diff changeset
1869 pp_character (m_pp, '0' + (column / 100) % 10);
kono
parents:
diff changeset
1870 else
kono
parents:
diff changeset
1871 pp_space (m_pp);
kono
parents:
diff changeset
1872 pp_newline (m_pp);
kono
parents:
diff changeset
1873 }
kono
parents:
diff changeset
1874
kono
parents:
diff changeset
1875 /* Tens. */
kono
parents:
diff changeset
1876 pp_space (m_pp);
kono
parents:
diff changeset
1877 for (int column = 1 + m_x_offset; column <= max_column; column++)
kono
parents:
diff changeset
1878 if (0 == column % 10)
kono
parents:
diff changeset
1879 pp_character (m_pp, '0' + (column / 10) % 10);
kono
parents:
diff changeset
1880 else
kono
parents:
diff changeset
1881 pp_space (m_pp);
kono
parents:
diff changeset
1882 pp_newline (m_pp);
kono
parents:
diff changeset
1883
kono
parents:
diff changeset
1884 /* Units. */
kono
parents:
diff changeset
1885 pp_space (m_pp);
kono
parents:
diff changeset
1886 for (int column = 1 + m_x_offset; column <= max_column; column++)
kono
parents:
diff changeset
1887 pp_character (m_pp, '0' + (column % 10));
kono
parents:
diff changeset
1888 pp_newline (m_pp);
kono
parents:
diff changeset