annotate gcc/diagnostic-show-locus.c @ 118:fd00160c1b76

ifdef TARGET_64BIT
author mir3636
date Tue, 27 Feb 2018 15:01:35 +0900
parents 04ced10e8804
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
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
1889 }
kono
parents:
diff changeset
1890
kono
parents:
diff changeset
1891 /* Print leading fix-its (for new lines inserted before the source line)
kono
parents:
diff changeset
1892 then the source line, followed by an annotation line
kono
parents:
diff changeset
1893 consisting of any caret/underlines, then any fixits.
kono
parents:
diff changeset
1894 If the source line can't be read, print nothing. */
kono
parents:
diff changeset
1895 void
kono
parents:
diff changeset
1896 layout::print_line (int row)
kono
parents:
diff changeset
1897 {
kono
parents:
diff changeset
1898 int line_width;
kono
parents:
diff changeset
1899 const char *line = location_get_source_line (m_exploc.file, row,
kono
parents:
diff changeset
1900 &line_width);
kono
parents:
diff changeset
1901 if (!line)
kono
parents:
diff changeset
1902 return;
kono
parents:
diff changeset
1903
kono
parents:
diff changeset
1904 line_bounds lbounds;
kono
parents:
diff changeset
1905 print_leading_fixits (row);
kono
parents:
diff changeset
1906 print_source_line (row, line, line_width, &lbounds);
kono
parents:
diff changeset
1907 if (should_print_annotation_line_p (row))
kono
parents:
diff changeset
1908 print_annotation_line (row, lbounds);
kono
parents:
diff changeset
1909 print_trailing_fixits (row);
kono
parents:
diff changeset
1910 }
kono
parents:
diff changeset
1911
kono
parents:
diff changeset
1912 } /* End of anonymous namespace. */
kono
parents:
diff changeset
1913
kono
parents:
diff changeset
1914 /* If LOC is within the spans of lines that will already be printed for
kono
parents:
diff changeset
1915 this gcc_rich_location, then add it as a secondary location and return true.
kono
parents:
diff changeset
1916
kono
parents:
diff changeset
1917 Otherwise return false. */
kono
parents:
diff changeset
1918
kono
parents:
diff changeset
1919 bool
kono
parents:
diff changeset
1920 gcc_rich_location::add_location_if_nearby (location_t loc)
kono
parents:
diff changeset
1921 {
kono
parents:
diff changeset
1922 /* Use the layout location-handling logic to sanitize LOC,
kono
parents:
diff changeset
1923 filtering it to the current line spans within a temporary
kono
parents:
diff changeset
1924 layout instance. */
kono
parents:
diff changeset
1925 layout layout (global_dc, this, DK_ERROR);
kono
parents:
diff changeset
1926 location_range loc_range;
kono
parents:
diff changeset
1927 loc_range.m_loc = loc;
kono
parents:
diff changeset
1928 loc_range.m_show_caret_p = false;
kono
parents:
diff changeset
1929 if (!layout.maybe_add_location_range (&loc_range, true))
kono
parents:
diff changeset
1930 return false;
kono
parents:
diff changeset
1931
kono
parents:
diff changeset
1932 add_range (loc, false);
kono
parents:
diff changeset
1933 return true;
kono
parents:
diff changeset
1934 }
kono
parents:
diff changeset
1935
kono
parents:
diff changeset
1936 /* Print the physical source code corresponding to the location of
kono
parents:
diff changeset
1937 this diagnostic, with additional annotations. */
kono
parents:
diff changeset
1938
kono
parents:
diff changeset
1939 void
kono
parents:
diff changeset
1940 diagnostic_show_locus (diagnostic_context * context,
kono
parents:
diff changeset
1941 rich_location *richloc,
kono
parents:
diff changeset
1942 diagnostic_t diagnostic_kind)
kono
parents:
diff changeset
1943 {
kono
parents:
diff changeset
1944 pp_newline (context->printer);
kono
parents:
diff changeset
1945
kono
parents:
diff changeset
1946 location_t loc = richloc->get_loc ();
kono
parents:
diff changeset
1947 /* Do nothing if source-printing has been disabled. */
kono
parents:
diff changeset
1948 if (!context->show_caret)
kono
parents:
diff changeset
1949 return;
kono
parents:
diff changeset
1950
kono
parents:
diff changeset
1951 /* Don't attempt to print source for UNKNOWN_LOCATION and for builtins. */
kono
parents:
diff changeset
1952 if (loc <= BUILTINS_LOCATION)
kono
parents:
diff changeset
1953 return;
kono
parents:
diff changeset
1954
kono
parents:
diff changeset
1955 /* Don't print the same source location twice in a row, unless we have
kono
parents:
diff changeset
1956 fix-it hints. */
kono
parents:
diff changeset
1957 if (loc == context->last_location
kono
parents:
diff changeset
1958 && richloc->get_num_fixit_hints () == 0)
kono
parents:
diff changeset
1959 return;
kono
parents:
diff changeset
1960
kono
parents:
diff changeset
1961 context->last_location = loc;
kono
parents:
diff changeset
1962
kono
parents:
diff changeset
1963 const char *saved_prefix = pp_get_prefix (context->printer);
kono
parents:
diff changeset
1964 pp_set_prefix (context->printer, NULL);
kono
parents:
diff changeset
1965
kono
parents:
diff changeset
1966 layout layout (context, richloc, diagnostic_kind);
kono
parents:
diff changeset
1967 for (int line_span_idx = 0; line_span_idx < layout.get_num_line_spans ();
kono
parents:
diff changeset
1968 line_span_idx++)
kono
parents:
diff changeset
1969 {
kono
parents:
diff changeset
1970 const line_span *line_span = layout.get_line_span (line_span_idx);
kono
parents:
diff changeset
1971 if (layout.print_heading_for_line_span_index_p (line_span_idx))
kono
parents:
diff changeset
1972 {
kono
parents:
diff changeset
1973 expanded_location exploc = layout.get_expanded_location (line_span);
kono
parents:
diff changeset
1974 context->start_span (context, exploc);
kono
parents:
diff changeset
1975 }
kono
parents:
diff changeset
1976 int last_line = line_span->get_last_line ();
kono
parents:
diff changeset
1977 for (int row = line_span->get_first_line (); row <= last_line; row++)
kono
parents:
diff changeset
1978 layout.print_line (row);
kono
parents:
diff changeset
1979 }
kono
parents:
diff changeset
1980
kono
parents:
diff changeset
1981 pp_set_prefix (context->printer, saved_prefix);
kono
parents:
diff changeset
1982 }
kono
parents:
diff changeset
1983
kono
parents:
diff changeset
1984 #if CHECKING_P
kono
parents:
diff changeset
1985
kono
parents:
diff changeset
1986 namespace selftest {
kono
parents:
diff changeset
1987
kono
parents:
diff changeset
1988 /* Selftests for diagnostic_show_locus. */
kono
parents:
diff changeset
1989
kono
parents:
diff changeset
1990 /* Convenience subclass of diagnostic_context for testing
kono
parents:
diff changeset
1991 diagnostic_show_locus. */
kono
parents:
diff changeset
1992
kono
parents:
diff changeset
1993 class test_diagnostic_context : public diagnostic_context
kono
parents:
diff changeset
1994 {
kono
parents:
diff changeset
1995 public:
kono
parents:
diff changeset
1996 test_diagnostic_context ()
kono
parents:
diff changeset
1997 {
kono
parents:
diff changeset
1998 diagnostic_initialize (this, 0);
kono
parents:
diff changeset
1999 show_caret = true;
kono
parents:
diff changeset
2000 show_column = true;
kono
parents:
diff changeset
2001 start_span = start_span_cb;
kono
parents:
diff changeset
2002 }
kono
parents:
diff changeset
2003 ~test_diagnostic_context ()
kono
parents:
diff changeset
2004 {
kono
parents:
diff changeset
2005 diagnostic_finish (this);
kono
parents:
diff changeset
2006 }
kono
parents:
diff changeset
2007
kono
parents:
diff changeset
2008 /* Implementation of diagnostic_start_span_fn, hiding the
kono
parents:
diff changeset
2009 real filename (to avoid printing the names of tempfiles). */
kono
parents:
diff changeset
2010 static void
kono
parents:
diff changeset
2011 start_span_cb (diagnostic_context *context, expanded_location exploc)
kono
parents:
diff changeset
2012 {
kono
parents:
diff changeset
2013 exploc.file = "FILENAME";
kono
parents:
diff changeset
2014 default_diagnostic_start_span_fn (context, exploc);
kono
parents:
diff changeset
2015 }
kono
parents:
diff changeset
2016 };
kono
parents:
diff changeset
2017
kono
parents:
diff changeset
2018 /* Verify that diagnostic_show_locus works sanely on UNKNOWN_LOCATION. */
kono
parents:
diff changeset
2019
kono
parents:
diff changeset
2020 static void
kono
parents:
diff changeset
2021 test_diagnostic_show_locus_unknown_location ()
kono
parents:
diff changeset
2022 {
kono
parents:
diff changeset
2023 test_diagnostic_context dc;
kono
parents:
diff changeset
2024 rich_location richloc (line_table, UNKNOWN_LOCATION);
kono
parents:
diff changeset
2025 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2026 ASSERT_STREQ ("\n", pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2027 }
kono
parents:
diff changeset
2028
kono
parents:
diff changeset
2029 /* Verify that diagnostic_show_locus works sanely for various
kono
parents:
diff changeset
2030 single-line cases.
kono
parents:
diff changeset
2031
kono
parents:
diff changeset
2032 All of these work on the following 1-line source file:
kono
parents:
diff changeset
2033 .0000000001111111
kono
parents:
diff changeset
2034 .1234567890123456
kono
parents:
diff changeset
2035 "foo = bar.field;\n"
kono
parents:
diff changeset
2036 which is set up by test_diagnostic_show_locus_one_liner and calls
kono
parents:
diff changeset
2037 them. */
kono
parents:
diff changeset
2038
kono
parents:
diff changeset
2039 /* Just a caret. */
kono
parents:
diff changeset
2040
kono
parents:
diff changeset
2041 static void
kono
parents:
diff changeset
2042 test_one_liner_simple_caret ()
kono
parents:
diff changeset
2043 {
kono
parents:
diff changeset
2044 test_diagnostic_context dc;
kono
parents:
diff changeset
2045 location_t caret = linemap_position_for_column (line_table, 10);
kono
parents:
diff changeset
2046 rich_location richloc (line_table, caret);
kono
parents:
diff changeset
2047 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2048 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2049 " foo = bar.field;\n"
kono
parents:
diff changeset
2050 " ^\n",
kono
parents:
diff changeset
2051 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2052 }
kono
parents:
diff changeset
2053
kono
parents:
diff changeset
2054 /* Caret and range. */
kono
parents:
diff changeset
2055
kono
parents:
diff changeset
2056 static void
kono
parents:
diff changeset
2057 test_one_liner_caret_and_range ()
kono
parents:
diff changeset
2058 {
kono
parents:
diff changeset
2059 test_diagnostic_context dc;
kono
parents:
diff changeset
2060 location_t caret = linemap_position_for_column (line_table, 10);
kono
parents:
diff changeset
2061 location_t start = linemap_position_for_column (line_table, 7);
kono
parents:
diff changeset
2062 location_t finish = linemap_position_for_column (line_table, 15);
kono
parents:
diff changeset
2063 location_t loc = make_location (caret, start, finish);
kono
parents:
diff changeset
2064 rich_location richloc (line_table, loc);
kono
parents:
diff changeset
2065 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2066 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2067 " foo = bar.field;\n"
kono
parents:
diff changeset
2068 " ~~~^~~~~~\n",
kono
parents:
diff changeset
2069 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2070 }
kono
parents:
diff changeset
2071
kono
parents:
diff changeset
2072 /* Multiple ranges and carets. */
kono
parents:
diff changeset
2073
kono
parents:
diff changeset
2074 static void
kono
parents:
diff changeset
2075 test_one_liner_multiple_carets_and_ranges ()
kono
parents:
diff changeset
2076 {
kono
parents:
diff changeset
2077 test_diagnostic_context dc;
kono
parents:
diff changeset
2078 location_t foo
kono
parents:
diff changeset
2079 = make_location (linemap_position_for_column (line_table, 2),
kono
parents:
diff changeset
2080 linemap_position_for_column (line_table, 1),
kono
parents:
diff changeset
2081 linemap_position_for_column (line_table, 3));
kono
parents:
diff changeset
2082 dc.caret_chars[0] = 'A';
kono
parents:
diff changeset
2083
kono
parents:
diff changeset
2084 location_t bar
kono
parents:
diff changeset
2085 = make_location (linemap_position_for_column (line_table, 8),
kono
parents:
diff changeset
2086 linemap_position_for_column (line_table, 7),
kono
parents:
diff changeset
2087 linemap_position_for_column (line_table, 9));
kono
parents:
diff changeset
2088 dc.caret_chars[1] = 'B';
kono
parents:
diff changeset
2089
kono
parents:
diff changeset
2090 location_t field
kono
parents:
diff changeset
2091 = make_location (linemap_position_for_column (line_table, 13),
kono
parents:
diff changeset
2092 linemap_position_for_column (line_table, 11),
kono
parents:
diff changeset
2093 linemap_position_for_column (line_table, 15));
kono
parents:
diff changeset
2094 dc.caret_chars[2] = 'C';
kono
parents:
diff changeset
2095
kono
parents:
diff changeset
2096 rich_location richloc (line_table, foo);
kono
parents:
diff changeset
2097 richloc.add_range (bar, true);
kono
parents:
diff changeset
2098 richloc.add_range (field, true);
kono
parents:
diff changeset
2099 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2100 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2101 " foo = bar.field;\n"
kono
parents:
diff changeset
2102 " ~A~ ~B~ ~~C~~\n",
kono
parents:
diff changeset
2103 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2104 }
kono
parents:
diff changeset
2105
kono
parents:
diff changeset
2106 /* Insertion fix-it hint: adding an "&" to the front of "bar.field". */
kono
parents:
diff changeset
2107
kono
parents:
diff changeset
2108 static void
kono
parents:
diff changeset
2109 test_one_liner_fixit_insert_before ()
kono
parents:
diff changeset
2110 {
kono
parents:
diff changeset
2111 test_diagnostic_context dc;
kono
parents:
diff changeset
2112 location_t caret = linemap_position_for_column (line_table, 7);
kono
parents:
diff changeset
2113 rich_location richloc (line_table, caret);
kono
parents:
diff changeset
2114 richloc.add_fixit_insert_before ("&");
kono
parents:
diff changeset
2115 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2116 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2117 " foo = bar.field;\n"
kono
parents:
diff changeset
2118 " ^\n"
kono
parents:
diff changeset
2119 " &\n",
kono
parents:
diff changeset
2120 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2121 }
kono
parents:
diff changeset
2122
kono
parents:
diff changeset
2123 /* Insertion fix-it hint: adding a "[0]" after "foo". */
kono
parents:
diff changeset
2124
kono
parents:
diff changeset
2125 static void
kono
parents:
diff changeset
2126 test_one_liner_fixit_insert_after ()
kono
parents:
diff changeset
2127 {
kono
parents:
diff changeset
2128 test_diagnostic_context dc;
kono
parents:
diff changeset
2129 location_t start = linemap_position_for_column (line_table, 1);
kono
parents:
diff changeset
2130 location_t finish = linemap_position_for_column (line_table, 3);
kono
parents:
diff changeset
2131 location_t foo = make_location (start, start, finish);
kono
parents:
diff changeset
2132 rich_location richloc (line_table, foo);
kono
parents:
diff changeset
2133 richloc.add_fixit_insert_after ("[0]");
kono
parents:
diff changeset
2134 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2135 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2136 " foo = bar.field;\n"
kono
parents:
diff changeset
2137 " ^~~\n"
kono
parents:
diff changeset
2138 " [0]\n",
kono
parents:
diff changeset
2139 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2140 }
kono
parents:
diff changeset
2141
kono
parents:
diff changeset
2142 /* Removal fix-it hint: removal of the ".field". */
kono
parents:
diff changeset
2143
kono
parents:
diff changeset
2144 static void
kono
parents:
diff changeset
2145 test_one_liner_fixit_remove ()
kono
parents:
diff changeset
2146 {
kono
parents:
diff changeset
2147 test_diagnostic_context dc;
kono
parents:
diff changeset
2148 location_t start = linemap_position_for_column (line_table, 10);
kono
parents:
diff changeset
2149 location_t finish = linemap_position_for_column (line_table, 15);
kono
parents:
diff changeset
2150 location_t dot = make_location (start, start, finish);
kono
parents:
diff changeset
2151 rich_location richloc (line_table, dot);
kono
parents:
diff changeset
2152 richloc.add_fixit_remove ();
kono
parents:
diff changeset
2153 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2154 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2155 " foo = bar.field;\n"
kono
parents:
diff changeset
2156 " ^~~~~~\n"
kono
parents:
diff changeset
2157 " ------\n",
kono
parents:
diff changeset
2158 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2159 }
kono
parents:
diff changeset
2160
kono
parents:
diff changeset
2161 /* Replace fix-it hint: replacing "field" with "m_field". */
kono
parents:
diff changeset
2162
kono
parents:
diff changeset
2163 static void
kono
parents:
diff changeset
2164 test_one_liner_fixit_replace ()
kono
parents:
diff changeset
2165 {
kono
parents:
diff changeset
2166 test_diagnostic_context dc;
kono
parents:
diff changeset
2167 location_t start = linemap_position_for_column (line_table, 11);
kono
parents:
diff changeset
2168 location_t finish = linemap_position_for_column (line_table, 15);
kono
parents:
diff changeset
2169 location_t field = make_location (start, start, finish);
kono
parents:
diff changeset
2170 rich_location richloc (line_table, field);
kono
parents:
diff changeset
2171 richloc.add_fixit_replace ("m_field");
kono
parents:
diff changeset
2172 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2173 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2174 " foo = bar.field;\n"
kono
parents:
diff changeset
2175 " ^~~~~\n"
kono
parents:
diff changeset
2176 " m_field\n",
kono
parents:
diff changeset
2177 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2178 }
kono
parents:
diff changeset
2179
kono
parents:
diff changeset
2180 /* Replace fix-it hint: replacing "field" with "m_field",
kono
parents:
diff changeset
2181 but where the caret was elsewhere. */
kono
parents:
diff changeset
2182
kono
parents:
diff changeset
2183 static void
kono
parents:
diff changeset
2184 test_one_liner_fixit_replace_non_equal_range ()
kono
parents:
diff changeset
2185 {
kono
parents:
diff changeset
2186 test_diagnostic_context dc;
kono
parents:
diff changeset
2187 location_t equals = linemap_position_for_column (line_table, 5);
kono
parents:
diff changeset
2188 location_t start = linemap_position_for_column (line_table, 11);
kono
parents:
diff changeset
2189 location_t finish = linemap_position_for_column (line_table, 15);
kono
parents:
diff changeset
2190 rich_location richloc (line_table, equals);
kono
parents:
diff changeset
2191 source_range range;
kono
parents:
diff changeset
2192 range.m_start = start;
kono
parents:
diff changeset
2193 range.m_finish = finish;
kono
parents:
diff changeset
2194 richloc.add_fixit_replace (range, "m_field");
kono
parents:
diff changeset
2195 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2196 /* The replacement range is not indicated in the annotation line, so
kono
parents:
diff changeset
2197 it should be indicated via an additional underline. */
kono
parents:
diff changeset
2198 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2199 " foo = bar.field;\n"
kono
parents:
diff changeset
2200 " ^\n"
kono
parents:
diff changeset
2201 " -----\n"
kono
parents:
diff changeset
2202 " m_field\n",
kono
parents:
diff changeset
2203 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2204 }
kono
parents:
diff changeset
2205
kono
parents:
diff changeset
2206 /* Replace fix-it hint: replacing "field" with "m_field",
kono
parents:
diff changeset
2207 where the caret was elsewhere, but where a secondary range
kono
parents:
diff changeset
2208 exactly covers "field". */
kono
parents:
diff changeset
2209
kono
parents:
diff changeset
2210 static void
kono
parents:
diff changeset
2211 test_one_liner_fixit_replace_equal_secondary_range ()
kono
parents:
diff changeset
2212 {
kono
parents:
diff changeset
2213 test_diagnostic_context dc;
kono
parents:
diff changeset
2214 location_t equals = linemap_position_for_column (line_table, 5);
kono
parents:
diff changeset
2215 location_t start = linemap_position_for_column (line_table, 11);
kono
parents:
diff changeset
2216 location_t finish = linemap_position_for_column (line_table, 15);
kono
parents:
diff changeset
2217 rich_location richloc (line_table, equals);
kono
parents:
diff changeset
2218 location_t field = make_location (start, start, finish);
kono
parents:
diff changeset
2219 richloc.add_range (field, false);
kono
parents:
diff changeset
2220 richloc.add_fixit_replace (field, "m_field");
kono
parents:
diff changeset
2221 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2222 /* The replacement range is indicated in the annotation line,
kono
parents:
diff changeset
2223 so it shouldn't be indicated via an additional underline. */
kono
parents:
diff changeset
2224 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2225 " foo = bar.field;\n"
kono
parents:
diff changeset
2226 " ^ ~~~~~\n"
kono
parents:
diff changeset
2227 " m_field\n",
kono
parents:
diff changeset
2228 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2229 }
kono
parents:
diff changeset
2230
kono
parents:
diff changeset
2231 /* Verify that we can use ad-hoc locations when adding fixits to a
kono
parents:
diff changeset
2232 rich_location. */
kono
parents:
diff changeset
2233
kono
parents:
diff changeset
2234 static void
kono
parents:
diff changeset
2235 test_one_liner_fixit_validation_adhoc_locations ()
kono
parents:
diff changeset
2236 {
kono
parents:
diff changeset
2237 /* Generate a range that's too long to be packed, so must
kono
parents:
diff changeset
2238 be stored as an ad-hoc location (given the defaults
kono
parents:
diff changeset
2239 of 5 bits or 0 bits of packed range); 41 columns > 2**5. */
kono
parents:
diff changeset
2240 const location_t c7 = linemap_position_for_column (line_table, 7);
kono
parents:
diff changeset
2241 const location_t c47 = linemap_position_for_column (line_table, 47);
kono
parents:
diff changeset
2242 const location_t loc = make_location (c7, c7, c47);
kono
parents:
diff changeset
2243
kono
parents:
diff changeset
2244 if (c47 > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
2245 return;
kono
parents:
diff changeset
2246
kono
parents:
diff changeset
2247 ASSERT_TRUE (IS_ADHOC_LOC (loc));
kono
parents:
diff changeset
2248
kono
parents:
diff changeset
2249 /* Insert. */
kono
parents:
diff changeset
2250 {
kono
parents:
diff changeset
2251 rich_location richloc (line_table, loc);
kono
parents:
diff changeset
2252 richloc.add_fixit_insert_before (loc, "test");
kono
parents:
diff changeset
2253 /* It should not have been discarded by the validator. */
kono
parents:
diff changeset
2254 ASSERT_EQ (1, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2255
kono
parents:
diff changeset
2256 test_diagnostic_context dc;
kono
parents:
diff changeset
2257 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2258 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2259 " foo = bar.field;\n"
kono
parents:
diff changeset
2260 " ^~~~~~~~~~ \n"
kono
parents:
diff changeset
2261 " test\n",
kono
parents:
diff changeset
2262 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2263 }
kono
parents:
diff changeset
2264
kono
parents:
diff changeset
2265 /* Remove. */
kono
parents:
diff changeset
2266 {
kono
parents:
diff changeset
2267 rich_location richloc (line_table, loc);
kono
parents:
diff changeset
2268 source_range range = source_range::from_locations (loc, c47);
kono
parents:
diff changeset
2269 richloc.add_fixit_remove (range);
kono
parents:
diff changeset
2270 /* It should not have been discarded by the validator. */
kono
parents:
diff changeset
2271 ASSERT_EQ (1, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2272
kono
parents:
diff changeset
2273 test_diagnostic_context dc;
kono
parents:
diff changeset
2274 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2275 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2276 " foo = bar.field;\n"
kono
parents:
diff changeset
2277 " ^~~~~~~~~~ \n"
kono
parents:
diff changeset
2278 " -----------------------------------------\n",
kono
parents:
diff changeset
2279 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2280 }
kono
parents:
diff changeset
2281
kono
parents:
diff changeset
2282 /* Replace. */
kono
parents:
diff changeset
2283 {
kono
parents:
diff changeset
2284 rich_location richloc (line_table, loc);
kono
parents:
diff changeset
2285 source_range range = source_range::from_locations (loc, c47);
kono
parents:
diff changeset
2286 richloc.add_fixit_replace (range, "test");
kono
parents:
diff changeset
2287 /* It should not have been discarded by the validator. */
kono
parents:
diff changeset
2288 ASSERT_EQ (1, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2289
kono
parents:
diff changeset
2290 test_diagnostic_context dc;
kono
parents:
diff changeset
2291 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2292 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2293 " foo = bar.field;\n"
kono
parents:
diff changeset
2294 " ^~~~~~~~~~ \n"
kono
parents:
diff changeset
2295 " test\n",
kono
parents:
diff changeset
2296 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2297 }
kono
parents:
diff changeset
2298 }
kono
parents:
diff changeset
2299
kono
parents:
diff changeset
2300 /* Test of consolidating insertions at the same location. */
kono
parents:
diff changeset
2301
kono
parents:
diff changeset
2302 static void
kono
parents:
diff changeset
2303 test_one_liner_many_fixits_1 ()
kono
parents:
diff changeset
2304 {
kono
parents:
diff changeset
2305 test_diagnostic_context dc;
kono
parents:
diff changeset
2306 location_t equals = linemap_position_for_column (line_table, 5);
kono
parents:
diff changeset
2307 rich_location richloc (line_table, equals);
kono
parents:
diff changeset
2308 for (int i = 0; i < 19; i++)
kono
parents:
diff changeset
2309 richloc.add_fixit_insert_before ("a");
kono
parents:
diff changeset
2310 ASSERT_EQ (1, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2311 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2312 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2313 " foo = bar.field;\n"
kono
parents:
diff changeset
2314 " ^\n"
kono
parents:
diff changeset
2315 " aaaaaaaaaaaaaaaaaaa\n",
kono
parents:
diff changeset
2316 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2317 }
kono
parents:
diff changeset
2318
kono
parents:
diff changeset
2319 /* Ensure that we can add an arbitrary number of fix-it hints to a
kono
parents:
diff changeset
2320 rich_location, even if they are not consolidated. */
kono
parents:
diff changeset
2321
kono
parents:
diff changeset
2322 static void
kono
parents:
diff changeset
2323 test_one_liner_many_fixits_2 ()
kono
parents:
diff changeset
2324 {
kono
parents:
diff changeset
2325 test_diagnostic_context dc;
kono
parents:
diff changeset
2326 location_t equals = linemap_position_for_column (line_table, 5);
kono
parents:
diff changeset
2327 rich_location richloc (line_table, equals);
kono
parents:
diff changeset
2328 for (int i = 0; i < 19; i++)
kono
parents:
diff changeset
2329 {
kono
parents:
diff changeset
2330 location_t loc = linemap_position_for_column (line_table, i * 2);
kono
parents:
diff changeset
2331 richloc.add_fixit_insert_before (loc, "a");
kono
parents:
diff changeset
2332 }
kono
parents:
diff changeset
2333 ASSERT_EQ (19, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2334 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2335 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2336 " foo = bar.field;\n"
kono
parents:
diff changeset
2337 " ^\n"
kono
parents:
diff changeset
2338 "a a a a a a a a a a a a a a a a a a a\n",
kono
parents:
diff changeset
2339 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2340 }
kono
parents:
diff changeset
2341
kono
parents:
diff changeset
2342 /* Run the various one-liner tests. */
kono
parents:
diff changeset
2343
kono
parents:
diff changeset
2344 static void
kono
parents:
diff changeset
2345 test_diagnostic_show_locus_one_liner (const line_table_case &case_)
kono
parents:
diff changeset
2346 {
kono
parents:
diff changeset
2347 /* Create a tempfile and write some text to it.
kono
parents:
diff changeset
2348 ....................0000000001111111.
kono
parents:
diff changeset
2349 ....................1234567890123456. */
kono
parents:
diff changeset
2350 const char *content = "foo = bar.field;\n";
kono
parents:
diff changeset
2351 temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
kono
parents:
diff changeset
2352 line_table_test ltt (case_);
kono
parents:
diff changeset
2353
kono
parents:
diff changeset
2354 linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
kono
parents:
diff changeset
2355
kono
parents:
diff changeset
2356 location_t line_end = linemap_position_for_column (line_table, 16);
kono
parents:
diff changeset
2357
kono
parents:
diff changeset
2358 /* Don't attempt to run the tests if column data might be unavailable. */
kono
parents:
diff changeset
2359 if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
2360 return;
kono
parents:
diff changeset
2361
kono
parents:
diff changeset
2362 ASSERT_STREQ (tmp.get_filename (), LOCATION_FILE (line_end));
kono
parents:
diff changeset
2363 ASSERT_EQ (1, LOCATION_LINE (line_end));
kono
parents:
diff changeset
2364 ASSERT_EQ (16, LOCATION_COLUMN (line_end));
kono
parents:
diff changeset
2365
kono
parents:
diff changeset
2366 test_one_liner_simple_caret ();
kono
parents:
diff changeset
2367 test_one_liner_caret_and_range ();
kono
parents:
diff changeset
2368 test_one_liner_multiple_carets_and_ranges ();
kono
parents:
diff changeset
2369 test_one_liner_fixit_insert_before ();
kono
parents:
diff changeset
2370 test_one_liner_fixit_insert_after ();
kono
parents:
diff changeset
2371 test_one_liner_fixit_remove ();
kono
parents:
diff changeset
2372 test_one_liner_fixit_replace ();
kono
parents:
diff changeset
2373 test_one_liner_fixit_replace_non_equal_range ();
kono
parents:
diff changeset
2374 test_one_liner_fixit_replace_equal_secondary_range ();
kono
parents:
diff changeset
2375 test_one_liner_fixit_validation_adhoc_locations ();
kono
parents:
diff changeset
2376 test_one_liner_many_fixits_1 ();
kono
parents:
diff changeset
2377 test_one_liner_many_fixits_2 ();
kono
parents:
diff changeset
2378 }
kono
parents:
diff changeset
2379
kono
parents:
diff changeset
2380 /* Verify that gcc_rich_location::add_location_if_nearby works. */
kono
parents:
diff changeset
2381
kono
parents:
diff changeset
2382 static void
kono
parents:
diff changeset
2383 test_add_location_if_nearby (const line_table_case &case_)
kono
parents:
diff changeset
2384 {
kono
parents:
diff changeset
2385 /* Create a tempfile and write some text to it.
kono
parents:
diff changeset
2386 ...000000000111111111122222222223333333333.
kono
parents:
diff changeset
2387 ...123456789012345678901234567890123456789. */
kono
parents:
diff changeset
2388 const char *content
kono
parents:
diff changeset
2389 = ("struct same_line { double x; double y; ;\n" /* line 1. */
kono
parents:
diff changeset
2390 "struct different_line\n" /* line 2. */
kono
parents:
diff changeset
2391 "{\n" /* line 3. */
kono
parents:
diff changeset
2392 " double x;\n" /* line 4. */
kono
parents:
diff changeset
2393 " double y;\n" /* line 5. */
kono
parents:
diff changeset
2394 ";\n"); /* line 6. */
kono
parents:
diff changeset
2395 temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
kono
parents:
diff changeset
2396 line_table_test ltt (case_);
kono
parents:
diff changeset
2397
kono
parents:
diff changeset
2398 const line_map_ordinary *ord_map
kono
parents:
diff changeset
2399 = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
kono
parents:
diff changeset
2400 tmp.get_filename (), 0));
kono
parents:
diff changeset
2401
kono
parents:
diff changeset
2402 linemap_line_start (line_table, 1, 100);
kono
parents:
diff changeset
2403
kono
parents:
diff changeset
2404 const location_t final_line_end
kono
parents:
diff changeset
2405 = linemap_position_for_line_and_column (line_table, ord_map, 6, 7);
kono
parents:
diff changeset
2406
kono
parents:
diff changeset
2407 /* Don't attempt to run the tests if column data might be unavailable. */
kono
parents:
diff changeset
2408 if (final_line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
2409 return;
kono
parents:
diff changeset
2410
kono
parents:
diff changeset
2411 /* Test of add_location_if_nearby on the same line as the
kono
parents:
diff changeset
2412 primary location. */
kono
parents:
diff changeset
2413 {
kono
parents:
diff changeset
2414 const location_t missing_close_brace_1_39
kono
parents:
diff changeset
2415 = linemap_position_for_line_and_column (line_table, ord_map, 1, 39);
kono
parents:
diff changeset
2416 const location_t matching_open_brace_1_18
kono
parents:
diff changeset
2417 = linemap_position_for_line_and_column (line_table, ord_map, 1, 18);
kono
parents:
diff changeset
2418 gcc_rich_location richloc (missing_close_brace_1_39);
kono
parents:
diff changeset
2419 bool added = richloc.add_location_if_nearby (matching_open_brace_1_18);
kono
parents:
diff changeset
2420 ASSERT_TRUE (added);
kono
parents:
diff changeset
2421 ASSERT_EQ (2, richloc.get_num_locations ());
kono
parents:
diff changeset
2422 test_diagnostic_context dc;
kono
parents:
diff changeset
2423 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2424 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2425 " struct same_line { double x; double y; ;\n"
kono
parents:
diff changeset
2426 " ~ ^\n",
kono
parents:
diff changeset
2427 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2428 }
kono
parents:
diff changeset
2429
kono
parents:
diff changeset
2430 /* Test of add_location_if_nearby on a different line to the
kono
parents:
diff changeset
2431 primary location. */
kono
parents:
diff changeset
2432 {
kono
parents:
diff changeset
2433 const location_t missing_close_brace_6_1
kono
parents:
diff changeset
2434 = linemap_position_for_line_and_column (line_table, ord_map, 6, 1);
kono
parents:
diff changeset
2435 const location_t matching_open_brace_3_1
kono
parents:
diff changeset
2436 = linemap_position_for_line_and_column (line_table, ord_map, 3, 1);
kono
parents:
diff changeset
2437 gcc_rich_location richloc (missing_close_brace_6_1);
kono
parents:
diff changeset
2438 bool added = richloc.add_location_if_nearby (matching_open_brace_3_1);
kono
parents:
diff changeset
2439 ASSERT_FALSE (added);
kono
parents:
diff changeset
2440 ASSERT_EQ (1, richloc.get_num_locations ());
kono
parents:
diff changeset
2441 }
kono
parents:
diff changeset
2442 }
kono
parents:
diff changeset
2443
kono
parents:
diff changeset
2444 /* Verify that we print fixits even if they only affect lines
kono
parents:
diff changeset
2445 outside those covered by the ranges in the rich_location. */
kono
parents:
diff changeset
2446
kono
parents:
diff changeset
2447 static void
kono
parents:
diff changeset
2448 test_diagnostic_show_locus_fixit_lines (const line_table_case &case_)
kono
parents:
diff changeset
2449 {
kono
parents:
diff changeset
2450 /* Create a tempfile and write some text to it.
kono
parents:
diff changeset
2451 ...000000000111111111122222222223333333333.
kono
parents:
diff changeset
2452 ...123456789012345678901234567890123456789. */
kono
parents:
diff changeset
2453 const char *content
kono
parents:
diff changeset
2454 = ("struct point { double x; double y; };\n" /* line 1. */
kono
parents:
diff changeset
2455 "struct point origin = {x: 0.0,\n" /* line 2. */
kono
parents:
diff changeset
2456 " y\n" /* line 3. */
kono
parents:
diff changeset
2457 "\n" /* line 4. */
kono
parents:
diff changeset
2458 "\n" /* line 5. */
kono
parents:
diff changeset
2459 " : 0.0};\n"); /* line 6. */
kono
parents:
diff changeset
2460 temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
kono
parents:
diff changeset
2461 line_table_test ltt (case_);
kono
parents:
diff changeset
2462
kono
parents:
diff changeset
2463 const line_map_ordinary *ord_map
kono
parents:
diff changeset
2464 = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
kono
parents:
diff changeset
2465 tmp.get_filename (), 0));
kono
parents:
diff changeset
2466
kono
parents:
diff changeset
2467 linemap_line_start (line_table, 1, 100);
kono
parents:
diff changeset
2468
kono
parents:
diff changeset
2469 const location_t final_line_end
kono
parents:
diff changeset
2470 = linemap_position_for_line_and_column (line_table, ord_map, 6, 36);
kono
parents:
diff changeset
2471
kono
parents:
diff changeset
2472 /* Don't attempt to run the tests if column data might be unavailable. */
kono
parents:
diff changeset
2473 if (final_line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
2474 return;
kono
parents:
diff changeset
2475
kono
parents:
diff changeset
2476 /* A pair of tests for modernizing the initializers to C99-style. */
kono
parents:
diff changeset
2477
kono
parents:
diff changeset
2478 /* The one-liner case (line 2). */
kono
parents:
diff changeset
2479 {
kono
parents:
diff changeset
2480 test_diagnostic_context dc;
kono
parents:
diff changeset
2481 const location_t x
kono
parents:
diff changeset
2482 = linemap_position_for_line_and_column (line_table, ord_map, 2, 24);
kono
parents:
diff changeset
2483 const location_t colon
kono
parents:
diff changeset
2484 = linemap_position_for_line_and_column (line_table, ord_map, 2, 25);
kono
parents:
diff changeset
2485 rich_location richloc (line_table, colon);
kono
parents:
diff changeset
2486 richloc.add_fixit_insert_before (x, ".");
kono
parents:
diff changeset
2487 richloc.add_fixit_replace (colon, "=");
kono
parents:
diff changeset
2488 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2489 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2490 " struct point origin = {x: 0.0,\n"
kono
parents:
diff changeset
2491 " ^\n"
kono
parents:
diff changeset
2492 " .=\n",
kono
parents:
diff changeset
2493 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2494 }
kono
parents:
diff changeset
2495
kono
parents:
diff changeset
2496 /* The multiline case. The caret for the rich_location is on line 6;
kono
parents:
diff changeset
2497 verify that insertion fixit on line 3 is still printed (and that
kono
parents:
diff changeset
2498 span starts are printed due to the gap between the span at line 3
kono
parents:
diff changeset
2499 and that at line 6). */
kono
parents:
diff changeset
2500 {
kono
parents:
diff changeset
2501 test_diagnostic_context dc;
kono
parents:
diff changeset
2502 const location_t y
kono
parents:
diff changeset
2503 = linemap_position_for_line_and_column (line_table, ord_map, 3, 24);
kono
parents:
diff changeset
2504 const location_t colon
kono
parents:
diff changeset
2505 = linemap_position_for_line_and_column (line_table, ord_map, 6, 25);
kono
parents:
diff changeset
2506 rich_location richloc (line_table, colon);
kono
parents:
diff changeset
2507 richloc.add_fixit_insert_before (y, ".");
kono
parents:
diff changeset
2508 richloc.add_fixit_replace (colon, "=");
kono
parents:
diff changeset
2509 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2510 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2511 "FILENAME:3:24:\n"
kono
parents:
diff changeset
2512 " y\n"
kono
parents:
diff changeset
2513 " .\n"
kono
parents:
diff changeset
2514 "FILENAME:6:25:\n"
kono
parents:
diff changeset
2515 " : 0.0};\n"
kono
parents:
diff changeset
2516 " ^\n"
kono
parents:
diff changeset
2517 " =\n",
kono
parents:
diff changeset
2518 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2519 }
kono
parents:
diff changeset
2520 }
kono
parents:
diff changeset
2521
kono
parents:
diff changeset
2522
kono
parents:
diff changeset
2523 /* Verify that fix-it hints are appropriately consolidated.
kono
parents:
diff changeset
2524
kono
parents:
diff changeset
2525 If any fix-it hints in a rich_location involve locations beyond
kono
parents:
diff changeset
2526 LINE_MAP_MAX_LOCATION_WITH_COLS, then we can't reliably apply
kono
parents:
diff changeset
2527 the fix-it as a whole, so there should be none.
kono
parents:
diff changeset
2528
kono
parents:
diff changeset
2529 Otherwise, verify that consecutive "replace" and "remove" fix-its
kono
parents:
diff changeset
2530 are merged, and that other fix-its remain separate. */
kono
parents:
diff changeset
2531
kono
parents:
diff changeset
2532 static void
kono
parents:
diff changeset
2533 test_fixit_consolidation (const line_table_case &case_)
kono
parents:
diff changeset
2534 {
kono
parents:
diff changeset
2535 line_table_test ltt (case_);
kono
parents:
diff changeset
2536
kono
parents:
diff changeset
2537 linemap_add (line_table, LC_ENTER, false, "test.c", 1);
kono
parents:
diff changeset
2538
kono
parents:
diff changeset
2539 const location_t c10 = linemap_position_for_column (line_table, 10);
kono
parents:
diff changeset
2540 const location_t c15 = linemap_position_for_column (line_table, 15);
kono
parents:
diff changeset
2541 const location_t c16 = linemap_position_for_column (line_table, 16);
kono
parents:
diff changeset
2542 const location_t c17 = linemap_position_for_column (line_table, 17);
kono
parents:
diff changeset
2543 const location_t c20 = linemap_position_for_column (line_table, 20);
kono
parents:
diff changeset
2544 const location_t c21 = linemap_position_for_column (line_table, 21);
kono
parents:
diff changeset
2545 const location_t caret = c10;
kono
parents:
diff changeset
2546
kono
parents:
diff changeset
2547 /* Insert + insert. */
kono
parents:
diff changeset
2548 {
kono
parents:
diff changeset
2549 rich_location richloc (line_table, caret);
kono
parents:
diff changeset
2550 richloc.add_fixit_insert_before (c10, "foo");
kono
parents:
diff changeset
2551 richloc.add_fixit_insert_before (c15, "bar");
kono
parents:
diff changeset
2552
kono
parents:
diff changeset
2553 if (c15 > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
2554 /* Bogus column info for 2nd fixit, so no fixits. */
kono
parents:
diff changeset
2555 ASSERT_EQ (0, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2556 else
kono
parents:
diff changeset
2557 /* They should not have been merged. */
kono
parents:
diff changeset
2558 ASSERT_EQ (2, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2559 }
kono
parents:
diff changeset
2560
kono
parents:
diff changeset
2561 /* Insert + replace. */
kono
parents:
diff changeset
2562 {
kono
parents:
diff changeset
2563 rich_location richloc (line_table, caret);
kono
parents:
diff changeset
2564 richloc.add_fixit_insert_before (c10, "foo");
kono
parents:
diff changeset
2565 richloc.add_fixit_replace (source_range::from_locations (c15, c17),
kono
parents:
diff changeset
2566 "bar");
kono
parents:
diff changeset
2567
kono
parents:
diff changeset
2568 if (c17 > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
2569 /* Bogus column info for 2nd fixit, so no fixits. */
kono
parents:
diff changeset
2570 ASSERT_EQ (0, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2571 else
kono
parents:
diff changeset
2572 /* They should not have been merged. */
kono
parents:
diff changeset
2573 ASSERT_EQ (2, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2574 }
kono
parents:
diff changeset
2575
kono
parents:
diff changeset
2576 /* Replace + non-consecutive insert. */
kono
parents:
diff changeset
2577 {
kono
parents:
diff changeset
2578 rich_location richloc (line_table, caret);
kono
parents:
diff changeset
2579 richloc.add_fixit_replace (source_range::from_locations (c10, c15),
kono
parents:
diff changeset
2580 "bar");
kono
parents:
diff changeset
2581 richloc.add_fixit_insert_before (c17, "foo");
kono
parents:
diff changeset
2582
kono
parents:
diff changeset
2583 if (c17 > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
2584 /* Bogus column info for 2nd fixit, so no fixits. */
kono
parents:
diff changeset
2585 ASSERT_EQ (0, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2586 else
kono
parents:
diff changeset
2587 /* They should not have been merged. */
kono
parents:
diff changeset
2588 ASSERT_EQ (2, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2589 }
kono
parents:
diff changeset
2590
kono
parents:
diff changeset
2591 /* Replace + non-consecutive replace. */
kono
parents:
diff changeset
2592 {
kono
parents:
diff changeset
2593 rich_location richloc (line_table, caret);
kono
parents:
diff changeset
2594 richloc.add_fixit_replace (source_range::from_locations (c10, c15),
kono
parents:
diff changeset
2595 "foo");
kono
parents:
diff changeset
2596 richloc.add_fixit_replace (source_range::from_locations (c17, c20),
kono
parents:
diff changeset
2597 "bar");
kono
parents:
diff changeset
2598
kono
parents:
diff changeset
2599 if (c20 > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
2600 /* Bogus column info for 2nd fixit, so no fixits. */
kono
parents:
diff changeset
2601 ASSERT_EQ (0, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2602 else
kono
parents:
diff changeset
2603 /* They should not have been merged. */
kono
parents:
diff changeset
2604 ASSERT_EQ (2, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2605 }
kono
parents:
diff changeset
2606
kono
parents:
diff changeset
2607 /* Replace + consecutive replace. */
kono
parents:
diff changeset
2608 {
kono
parents:
diff changeset
2609 rich_location richloc (line_table, caret);
kono
parents:
diff changeset
2610 richloc.add_fixit_replace (source_range::from_locations (c10, c15),
kono
parents:
diff changeset
2611 "foo");
kono
parents:
diff changeset
2612 richloc.add_fixit_replace (source_range::from_locations (c16, c20),
kono
parents:
diff changeset
2613 "bar");
kono
parents:
diff changeset
2614
kono
parents:
diff changeset
2615 if (c20 > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
2616 /* Bogus column info for 2nd fixit, so no fixits. */
kono
parents:
diff changeset
2617 ASSERT_EQ (0, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2618 else
kono
parents:
diff changeset
2619 {
kono
parents:
diff changeset
2620 /* They should have been merged into a single "replace". */
kono
parents:
diff changeset
2621 ASSERT_EQ (1, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2622 const fixit_hint *hint = richloc.get_fixit_hint (0);
kono
parents:
diff changeset
2623 ASSERT_STREQ ("foobar", hint->get_string ());
kono
parents:
diff changeset
2624 ASSERT_EQ (c10, hint->get_start_loc ());
kono
parents:
diff changeset
2625 ASSERT_EQ (c21, hint->get_next_loc ());
kono
parents:
diff changeset
2626 }
kono
parents:
diff changeset
2627 }
kono
parents:
diff changeset
2628
kono
parents:
diff changeset
2629 /* Replace + consecutive removal. */
kono
parents:
diff changeset
2630 {
kono
parents:
diff changeset
2631 rich_location richloc (line_table, caret);
kono
parents:
diff changeset
2632 richloc.add_fixit_replace (source_range::from_locations (c10, c15),
kono
parents:
diff changeset
2633 "foo");
kono
parents:
diff changeset
2634 richloc.add_fixit_remove (source_range::from_locations (c16, c20));
kono
parents:
diff changeset
2635
kono
parents:
diff changeset
2636 if (c20 > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
2637 /* Bogus column info for 2nd fixit, so no fixits. */
kono
parents:
diff changeset
2638 ASSERT_EQ (0, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2639 else
kono
parents:
diff changeset
2640 {
kono
parents:
diff changeset
2641 /* They should have been merged into a single replace, with the
kono
parents:
diff changeset
2642 range extended to cover that of the removal. */
kono
parents:
diff changeset
2643 ASSERT_EQ (1, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2644 const fixit_hint *hint = richloc.get_fixit_hint (0);
kono
parents:
diff changeset
2645 ASSERT_STREQ ("foo", hint->get_string ());
kono
parents:
diff changeset
2646 ASSERT_EQ (c10, hint->get_start_loc ());
kono
parents:
diff changeset
2647 ASSERT_EQ (c21, hint->get_next_loc ());
kono
parents:
diff changeset
2648 }
kono
parents:
diff changeset
2649 }
kono
parents:
diff changeset
2650
kono
parents:
diff changeset
2651 /* Consecutive removals. */
kono
parents:
diff changeset
2652 {
kono
parents:
diff changeset
2653 rich_location richloc (line_table, caret);
kono
parents:
diff changeset
2654 richloc.add_fixit_remove (source_range::from_locations (c10, c15));
kono
parents:
diff changeset
2655 richloc.add_fixit_remove (source_range::from_locations (c16, c20));
kono
parents:
diff changeset
2656
kono
parents:
diff changeset
2657 if (c20 > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
2658 /* Bogus column info for 2nd fixit, so no fixits. */
kono
parents:
diff changeset
2659 ASSERT_EQ (0, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2660 else
kono
parents:
diff changeset
2661 {
kono
parents:
diff changeset
2662 /* They should have been merged into a single "replace-with-empty". */
kono
parents:
diff changeset
2663 ASSERT_EQ (1, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2664 const fixit_hint *hint = richloc.get_fixit_hint (0);
kono
parents:
diff changeset
2665 ASSERT_STREQ ("", hint->get_string ());
kono
parents:
diff changeset
2666 ASSERT_EQ (c10, hint->get_start_loc ());
kono
parents:
diff changeset
2667 ASSERT_EQ (c21, hint->get_next_loc ());
kono
parents:
diff changeset
2668 }
kono
parents:
diff changeset
2669 }
kono
parents:
diff changeset
2670 }
kono
parents:
diff changeset
2671
kono
parents:
diff changeset
2672 /* Verify that the line_corrections machinery correctly prints
kono
parents:
diff changeset
2673 overlapping fixit-hints. */
kono
parents:
diff changeset
2674
kono
parents:
diff changeset
2675 static void
kono
parents:
diff changeset
2676 test_overlapped_fixit_printing (const line_table_case &case_)
kono
parents:
diff changeset
2677 {
kono
parents:
diff changeset
2678 /* Create a tempfile and write some text to it.
kono
parents:
diff changeset
2679 ...000000000111111111122222222223333333333.
kono
parents:
diff changeset
2680 ...123456789012345678901234567890123456789. */
kono
parents:
diff changeset
2681 const char *content
kono
parents:
diff changeset
2682 = (" foo *f = (foo *)ptr->field;\n");
kono
parents:
diff changeset
2683 temp_source_file tmp (SELFTEST_LOCATION, ".C", content);
kono
parents:
diff changeset
2684 line_table_test ltt (case_);
kono
parents:
diff changeset
2685
kono
parents:
diff changeset
2686 const line_map_ordinary *ord_map
kono
parents:
diff changeset
2687 = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
kono
parents:
diff changeset
2688 tmp.get_filename (), 0));
kono
parents:
diff changeset
2689
kono
parents:
diff changeset
2690 linemap_line_start (line_table, 1, 100);
kono
parents:
diff changeset
2691
kono
parents:
diff changeset
2692 const location_t final_line_end
kono
parents:
diff changeset
2693 = linemap_position_for_line_and_column (line_table, ord_map, 6, 36);
kono
parents:
diff changeset
2694
kono
parents:
diff changeset
2695 /* Don't attempt to run the tests if column data might be unavailable. */
kono
parents:
diff changeset
2696 if (final_line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
2697 return;
kono
parents:
diff changeset
2698
kono
parents:
diff changeset
2699 /* A test for converting a C-style cast to a C++-style cast. */
kono
parents:
diff changeset
2700 const location_t open_paren
kono
parents:
diff changeset
2701 = linemap_position_for_line_and_column (line_table, ord_map, 1, 12);
kono
parents:
diff changeset
2702 const location_t close_paren
kono
parents:
diff changeset
2703 = linemap_position_for_line_and_column (line_table, ord_map, 1, 18);
kono
parents:
diff changeset
2704 const location_t expr_start
kono
parents:
diff changeset
2705 = linemap_position_for_line_and_column (line_table, ord_map, 1, 19);
kono
parents:
diff changeset
2706 const location_t expr_finish
kono
parents:
diff changeset
2707 = linemap_position_for_line_and_column (line_table, ord_map, 1, 28);
kono
parents:
diff changeset
2708 const location_t expr = make_location (expr_start, expr_start, expr_finish);
kono
parents:
diff changeset
2709
kono
parents:
diff changeset
2710 /* Various examples of fix-it hints that aren't themselves consolidated,
kono
parents:
diff changeset
2711 but for which the *printing* may need consolidation. */
kono
parents:
diff changeset
2712
kono
parents:
diff changeset
2713 /* Example where 3 fix-it hints are printed as one. */
kono
parents:
diff changeset
2714 {
kono
parents:
diff changeset
2715 test_diagnostic_context dc;
kono
parents:
diff changeset
2716 rich_location richloc (line_table, expr);
kono
parents:
diff changeset
2717 richloc.add_fixit_replace (open_paren, "const_cast<");
kono
parents:
diff changeset
2718 richloc.add_fixit_replace (close_paren, "> (");
kono
parents:
diff changeset
2719 richloc.add_fixit_insert_after (")");
kono
parents:
diff changeset
2720
kono
parents:
diff changeset
2721 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2722 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2723 " foo *f = (foo *)ptr->field;\n"
kono
parents:
diff changeset
2724 " ^~~~~~~~~~\n"
kono
parents:
diff changeset
2725 " -----------------\n"
kono
parents:
diff changeset
2726 " const_cast<foo *> (ptr->field)\n",
kono
parents:
diff changeset
2727 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2728
kono
parents:
diff changeset
2729 /* Unit-test the line_corrections machinery. */
kono
parents:
diff changeset
2730 ASSERT_EQ (3, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2731 const fixit_hint *hint_0 = richloc.get_fixit_hint (0);
kono
parents:
diff changeset
2732 ASSERT_EQ (column_range (12, 12), get_affected_columns (hint_0));
kono
parents:
diff changeset
2733 ASSERT_EQ (column_range (12, 22), get_printed_columns (hint_0));
kono
parents:
diff changeset
2734 const fixit_hint *hint_1 = richloc.get_fixit_hint (1);
kono
parents:
diff changeset
2735 ASSERT_EQ (column_range (18, 18), get_affected_columns (hint_1));
kono
parents:
diff changeset
2736 ASSERT_EQ (column_range (18, 20), get_printed_columns (hint_1));
kono
parents:
diff changeset
2737 const fixit_hint *hint_2 = richloc.get_fixit_hint (2);
kono
parents:
diff changeset
2738 ASSERT_EQ (column_range (29, 28), get_affected_columns (hint_2));
kono
parents:
diff changeset
2739 ASSERT_EQ (column_range (29, 29), get_printed_columns (hint_2));
kono
parents:
diff changeset
2740
kono
parents:
diff changeset
2741 /* Add each hint in turn to a line_corrections instance,
kono
parents:
diff changeset
2742 and verify that they are consolidated into one correction instance
kono
parents:
diff changeset
2743 as expected. */
kono
parents:
diff changeset
2744 line_corrections lc (tmp.get_filename (), 1);
kono
parents:
diff changeset
2745
kono
parents:
diff changeset
2746 /* The first replace hint by itself. */
kono
parents:
diff changeset
2747 lc.add_hint (hint_0);
kono
parents:
diff changeset
2748 ASSERT_EQ (1, lc.m_corrections.length ());
kono
parents:
diff changeset
2749 ASSERT_EQ (column_range (12, 12), lc.m_corrections[0]->m_affected_columns);
kono
parents:
diff changeset
2750 ASSERT_EQ (column_range (12, 22), lc.m_corrections[0]->m_printed_columns);
kono
parents:
diff changeset
2751 ASSERT_STREQ ("const_cast<", lc.m_corrections[0]->m_text);
kono
parents:
diff changeset
2752
kono
parents:
diff changeset
2753 /* After the second replacement hint, they are printed together
kono
parents:
diff changeset
2754 as a replacement (along with the text between them). */
kono
parents:
diff changeset
2755 lc.add_hint (hint_1);
kono
parents:
diff changeset
2756 ASSERT_EQ (1, lc.m_corrections.length ());
kono
parents:
diff changeset
2757 ASSERT_STREQ ("const_cast<foo *> (", lc.m_corrections[0]->m_text);
kono
parents:
diff changeset
2758 ASSERT_EQ (column_range (12, 18), lc.m_corrections[0]->m_affected_columns);
kono
parents:
diff changeset
2759 ASSERT_EQ (column_range (12, 30), lc.m_corrections[0]->m_printed_columns);
kono
parents:
diff changeset
2760
kono
parents:
diff changeset
2761 /* After the final insertion hint, they are all printed together
kono
parents:
diff changeset
2762 as a replacement (along with the text between them). */
kono
parents:
diff changeset
2763 lc.add_hint (hint_2);
kono
parents:
diff changeset
2764 ASSERT_STREQ ("const_cast<foo *> (ptr->field)",
kono
parents:
diff changeset
2765 lc.m_corrections[0]->m_text);
kono
parents:
diff changeset
2766 ASSERT_EQ (1, lc.m_corrections.length ());
kono
parents:
diff changeset
2767 ASSERT_EQ (column_range (12, 28), lc.m_corrections[0]->m_affected_columns);
kono
parents:
diff changeset
2768 ASSERT_EQ (column_range (12, 41), lc.m_corrections[0]->m_printed_columns);
kono
parents:
diff changeset
2769 }
kono
parents:
diff changeset
2770
kono
parents:
diff changeset
2771 /* Example where two are consolidated during printing. */
kono
parents:
diff changeset
2772 {
kono
parents:
diff changeset
2773 test_diagnostic_context dc;
kono
parents:
diff changeset
2774 rich_location richloc (line_table, expr);
kono
parents:
diff changeset
2775 richloc.add_fixit_replace (open_paren, "CAST (");
kono
parents:
diff changeset
2776 richloc.add_fixit_replace (close_paren, ") (");
kono
parents:
diff changeset
2777 richloc.add_fixit_insert_after (")");
kono
parents:
diff changeset
2778
kono
parents:
diff changeset
2779 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2780 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2781 " foo *f = (foo *)ptr->field;\n"
kono
parents:
diff changeset
2782 " ^~~~~~~~~~\n"
kono
parents:
diff changeset
2783 " -\n"
kono
parents:
diff changeset
2784 " CAST (-\n"
kono
parents:
diff changeset
2785 " ) ( )\n",
kono
parents:
diff changeset
2786 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2787 }
kono
parents:
diff changeset
2788
kono
parents:
diff changeset
2789 /* Example where none are consolidated during printing. */
kono
parents:
diff changeset
2790 {
kono
parents:
diff changeset
2791 test_diagnostic_context dc;
kono
parents:
diff changeset
2792 rich_location richloc (line_table, expr);
kono
parents:
diff changeset
2793 richloc.add_fixit_replace (open_paren, "CST (");
kono
parents:
diff changeset
2794 richloc.add_fixit_replace (close_paren, ") (");
kono
parents:
diff changeset
2795 richloc.add_fixit_insert_after (")");
kono
parents:
diff changeset
2796
kono
parents:
diff changeset
2797 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2798 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2799 " foo *f = (foo *)ptr->field;\n"
kono
parents:
diff changeset
2800 " ^~~~~~~~~~\n"
kono
parents:
diff changeset
2801 " -\n"
kono
parents:
diff changeset
2802 " CST ( -\n"
kono
parents:
diff changeset
2803 " ) ( )\n",
kono
parents:
diff changeset
2804 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2805 }
kono
parents:
diff changeset
2806
kono
parents:
diff changeset
2807 /* Example of deletion fix-it hints. */
kono
parents:
diff changeset
2808 {
kono
parents:
diff changeset
2809 test_diagnostic_context dc;
kono
parents:
diff changeset
2810 rich_location richloc (line_table, expr);
kono
parents:
diff changeset
2811 richloc.add_fixit_insert_before (open_paren, "(bar *)");
kono
parents:
diff changeset
2812 source_range victim = {open_paren, close_paren};
kono
parents:
diff changeset
2813 richloc.add_fixit_remove (victim);
kono
parents:
diff changeset
2814
kono
parents:
diff changeset
2815 /* This case is actually handled by fixit-consolidation,
kono
parents:
diff changeset
2816 rather than by line_corrections. */
kono
parents:
diff changeset
2817 ASSERT_EQ (1, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2818
kono
parents:
diff changeset
2819 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2820 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2821 " foo *f = (foo *)ptr->field;\n"
kono
parents:
diff changeset
2822 " ^~~~~~~~~~\n"
kono
parents:
diff changeset
2823 " -------\n"
kono
parents:
diff changeset
2824 " (bar *)\n",
kono
parents:
diff changeset
2825 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2826 }
kono
parents:
diff changeset
2827
kono
parents:
diff changeset
2828 /* Example of deletion fix-it hints that would overlap. */
kono
parents:
diff changeset
2829 {
kono
parents:
diff changeset
2830 test_diagnostic_context dc;
kono
parents:
diff changeset
2831 rich_location richloc (line_table, expr);
kono
parents:
diff changeset
2832 richloc.add_fixit_insert_before (open_paren, "(longer *)");
kono
parents:
diff changeset
2833 source_range victim = {expr_start, expr_finish};
kono
parents:
diff changeset
2834 richloc.add_fixit_remove (victim);
kono
parents:
diff changeset
2835
kono
parents:
diff changeset
2836 /* These fixits are not consolidated. */
kono
parents:
diff changeset
2837 ASSERT_EQ (2, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2838
kono
parents:
diff changeset
2839 /* But the corrections are. */
kono
parents:
diff changeset
2840 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2841 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2842 " foo *f = (foo *)ptr->field;\n"
kono
parents:
diff changeset
2843 " ^~~~~~~~~~\n"
kono
parents:
diff changeset
2844 " -----------------\n"
kono
parents:
diff changeset
2845 " (longer *)(foo *)\n",
kono
parents:
diff changeset
2846 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2847 }
kono
parents:
diff changeset
2848
kono
parents:
diff changeset
2849 /* Example of insertion fix-it hints that would overlap. */
kono
parents:
diff changeset
2850 {
kono
parents:
diff changeset
2851 test_diagnostic_context dc;
kono
parents:
diff changeset
2852 rich_location richloc (line_table, expr);
kono
parents:
diff changeset
2853 richloc.add_fixit_insert_before (open_paren, "LONGER THAN THE CAST");
kono
parents:
diff changeset
2854 richloc.add_fixit_insert_after (close_paren, "TEST");
kono
parents:
diff changeset
2855
kono
parents:
diff changeset
2856 /* The first insertion is long enough that if printed naively,
kono
parents:
diff changeset
2857 it would overlap with the second.
kono
parents:
diff changeset
2858 Verify that they are printed as a single replacement. */
kono
parents:
diff changeset
2859 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2860 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2861 " foo *f = (foo *)ptr->field;\n"
kono
parents:
diff changeset
2862 " ^~~~~~~~~~\n"
kono
parents:
diff changeset
2863 " -------\n"
kono
parents:
diff changeset
2864 " LONGER THAN THE CAST(foo *)TEST\n",
kono
parents:
diff changeset
2865 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2866 }
kono
parents:
diff changeset
2867 }
kono
parents:
diff changeset
2868
kono
parents:
diff changeset
2869 /* Verify that the line_corrections machinery correctly prints
kono
parents:
diff changeset
2870 overlapping fixit-hints that have been added in the wrong
kono
parents:
diff changeset
2871 order.
kono
parents:
diff changeset
2872 Adapted from PR c/81405 seen on gcc.dg/init-excess-1.c*/
kono
parents:
diff changeset
2873
kono
parents:
diff changeset
2874 static void
kono
parents:
diff changeset
2875 test_overlapped_fixit_printing_2 (const line_table_case &case_)
kono
parents:
diff changeset
2876 {
kono
parents:
diff changeset
2877 /* Create a tempfile and write some text to it.
kono
parents:
diff changeset
2878 ...000000000111111111122222222223333333333.
kono
parents:
diff changeset
2879 ...123456789012345678901234567890123456789. */
kono
parents:
diff changeset
2880 const char *content
kono
parents:
diff changeset
2881 = ("int a5[][0][0] = { 1, 2 };\n");
kono
parents:
diff changeset
2882 temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
kono
parents:
diff changeset
2883 line_table_test ltt (case_);
kono
parents:
diff changeset
2884
kono
parents:
diff changeset
2885 const line_map_ordinary *ord_map
kono
parents:
diff changeset
2886 = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
kono
parents:
diff changeset
2887 tmp.get_filename (), 0));
kono
parents:
diff changeset
2888
kono
parents:
diff changeset
2889 linemap_line_start (line_table, 1, 100);
kono
parents:
diff changeset
2890
kono
parents:
diff changeset
2891 const location_t final_line_end
kono
parents:
diff changeset
2892 = linemap_position_for_line_and_column (line_table, ord_map, 1, 100);
kono
parents:
diff changeset
2893
kono
parents:
diff changeset
2894 /* Don't attempt to run the tests if column data might be unavailable. */
kono
parents:
diff changeset
2895 if (final_line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
2896 return;
kono
parents:
diff changeset
2897
kono
parents:
diff changeset
2898 const location_t col_1
kono
parents:
diff changeset
2899 = linemap_position_for_line_and_column (line_table, ord_map, 1, 1);
kono
parents:
diff changeset
2900 const location_t col_20
kono
parents:
diff changeset
2901 = linemap_position_for_line_and_column (line_table, ord_map, 1, 20);
kono
parents:
diff changeset
2902 const location_t col_21
kono
parents:
diff changeset
2903 = linemap_position_for_line_and_column (line_table, ord_map, 1, 21);
kono
parents:
diff changeset
2904 const location_t col_23
kono
parents:
diff changeset
2905 = linemap_position_for_line_and_column (line_table, ord_map, 1, 23);
kono
parents:
diff changeset
2906 const location_t col_25
kono
parents:
diff changeset
2907 = linemap_position_for_line_and_column (line_table, ord_map, 1, 25);
kono
parents:
diff changeset
2908
kono
parents:
diff changeset
2909 /* Two insertions, in the wrong order. */
kono
parents:
diff changeset
2910 {
kono
parents:
diff changeset
2911 rich_location richloc (line_table, col_20);
kono
parents:
diff changeset
2912 richloc.add_fixit_insert_before (col_23, "{");
kono
parents:
diff changeset
2913 richloc.add_fixit_insert_before (col_21, "}");
kono
parents:
diff changeset
2914
kono
parents:
diff changeset
2915 /* These fixits should be accepted; they can't be consolidated. */
kono
parents:
diff changeset
2916 ASSERT_EQ (2, richloc.get_num_fixit_hints ());
kono
parents:
diff changeset
2917 const fixit_hint *hint_0 = richloc.get_fixit_hint (0);
kono
parents:
diff changeset
2918 ASSERT_EQ (column_range (23, 22), get_affected_columns (hint_0));
kono
parents:
diff changeset
2919 ASSERT_EQ (column_range (23, 23), get_printed_columns (hint_0));
kono
parents:
diff changeset
2920 const fixit_hint *hint_1 = richloc.get_fixit_hint (1);
kono
parents:
diff changeset
2921 ASSERT_EQ (column_range (21, 20), get_affected_columns (hint_1));
kono
parents:
diff changeset
2922 ASSERT_EQ (column_range (21, 21), get_printed_columns (hint_1));
kono
parents:
diff changeset
2923
kono
parents:
diff changeset
2924 /* Verify that they're printed correctly. */
kono
parents:
diff changeset
2925 test_diagnostic_context dc;
kono
parents:
diff changeset
2926 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2927 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2928 " int a5[][0][0] = { 1, 2 };\n"
kono
parents:
diff changeset
2929 " ^\n"
kono
parents:
diff changeset
2930 " } {\n",
kono
parents:
diff changeset
2931 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2932 }
kono
parents:
diff changeset
2933
kono
parents:
diff changeset
2934 /* Various overlapping insertions, some occurring "out of order"
kono
parents:
diff changeset
2935 (reproducing the fix-it hints from PR c/81405). */
kono
parents:
diff changeset
2936 {
kono
parents:
diff changeset
2937 test_diagnostic_context dc;
kono
parents:
diff changeset
2938 rich_location richloc (line_table, col_20);
kono
parents:
diff changeset
2939
kono
parents:
diff changeset
2940 richloc.add_fixit_insert_before (col_20, "{{");
kono
parents:
diff changeset
2941 richloc.add_fixit_insert_before (col_21, "}}");
kono
parents:
diff changeset
2942 richloc.add_fixit_insert_before (col_23, "{");
kono
parents:
diff changeset
2943 richloc.add_fixit_insert_before (col_21, "}");
kono
parents:
diff changeset
2944 richloc.add_fixit_insert_before (col_23, "{{");
kono
parents:
diff changeset
2945 richloc.add_fixit_insert_before (col_25, "}");
kono
parents:
diff changeset
2946 richloc.add_fixit_insert_before (col_21, "}");
kono
parents:
diff changeset
2947 richloc.add_fixit_insert_before (col_1, "{");
kono
parents:
diff changeset
2948 richloc.add_fixit_insert_before (col_25, "}");
kono
parents:
diff changeset
2949 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2950 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2951 " int a5[][0][0] = { 1, 2 };\n"
kono
parents:
diff changeset
2952 " ^\n"
kono
parents:
diff changeset
2953 " { -----\n"
kono
parents:
diff changeset
2954 " {{1}}}}, {{{2 }}\n",
kono
parents:
diff changeset
2955 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2956 }
kono
parents:
diff changeset
2957 }
kono
parents:
diff changeset
2958
kono
parents:
diff changeset
2959 /* Insertion fix-it hint: adding a "break;" on a line by itself. */
kono
parents:
diff changeset
2960
kono
parents:
diff changeset
2961 static void
kono
parents:
diff changeset
2962 test_fixit_insert_containing_newline (const line_table_case &case_)
kono
parents:
diff changeset
2963 {
kono
parents:
diff changeset
2964 /* Create a tempfile and write some text to it.
kono
parents:
diff changeset
2965 .........................0000000001111111.
kono
parents:
diff changeset
2966 .........................1234567890123456. */
kono
parents:
diff changeset
2967 const char *old_content = (" case 'a':\n" /* line 1. */
kono
parents:
diff changeset
2968 " x = a;\n" /* line 2. */
kono
parents:
diff changeset
2969 " case 'b':\n" /* line 3. */
kono
parents:
diff changeset
2970 " x = b;\n");/* line 4. */
kono
parents:
diff changeset
2971
kono
parents:
diff changeset
2972 temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
kono
parents:
diff changeset
2973 line_table_test ltt (case_);
kono
parents:
diff changeset
2974 linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 3);
kono
parents:
diff changeset
2975
kono
parents:
diff changeset
2976 location_t case_start = linemap_position_for_column (line_table, 5);
kono
parents:
diff changeset
2977 location_t case_finish = linemap_position_for_column (line_table, 13);
kono
parents:
diff changeset
2978 location_t case_loc = make_location (case_start, case_start, case_finish);
kono
parents:
diff changeset
2979 location_t line_start = linemap_position_for_column (line_table, 1);
kono
parents:
diff changeset
2980
kono
parents:
diff changeset
2981 if (case_finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
2982 return;
kono
parents:
diff changeset
2983
kono
parents:
diff changeset
2984 /* Add a "break;" on a line by itself before line 3 i.e. before
kono
parents:
diff changeset
2985 column 1 of line 3. */
kono
parents:
diff changeset
2986 {
kono
parents:
diff changeset
2987 rich_location richloc (line_table, case_loc);
kono
parents:
diff changeset
2988 richloc.add_fixit_insert_before (line_start, " break;\n");
kono
parents:
diff changeset
2989 test_diagnostic_context dc;
kono
parents:
diff changeset
2990 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
2991 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
2992 "+ break;\n"
kono
parents:
diff changeset
2993 " case 'b':\n"
kono
parents:
diff changeset
2994 " ^~~~~~~~~\n",
kono
parents:
diff changeset
2995 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
2996 }
kono
parents:
diff changeset
2997
kono
parents:
diff changeset
2998 /* Verify that attempts to add text with a newline fail when the
kono
parents:
diff changeset
2999 insertion point is *not* at the start of a line. */
kono
parents:
diff changeset
3000 {
kono
parents:
diff changeset
3001 rich_location richloc (line_table, case_loc);
kono
parents:
diff changeset
3002 richloc.add_fixit_insert_before (case_start, "break;\n");
kono
parents:
diff changeset
3003 ASSERT_TRUE (richloc.seen_impossible_fixit_p ());
kono
parents:
diff changeset
3004 test_diagnostic_context dc;
kono
parents:
diff changeset
3005 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
3006 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
3007 " case 'b':\n"
kono
parents:
diff changeset
3008 " ^~~~~~~~~\n",
kono
parents:
diff changeset
3009 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
3010 }
kono
parents:
diff changeset
3011 }
kono
parents:
diff changeset
3012
kono
parents:
diff changeset
3013 /* Insertion fix-it hint: adding a "#include <stdio.h>\n" to the top
kono
parents:
diff changeset
3014 of the file, where the fix-it is printed in a different line-span
kono
parents:
diff changeset
3015 to the primary range of the diagnostic. */
kono
parents:
diff changeset
3016
kono
parents:
diff changeset
3017 static void
kono
parents:
diff changeset
3018 test_fixit_insert_containing_newline_2 (const line_table_case &case_)
kono
parents:
diff changeset
3019 {
kono
parents:
diff changeset
3020 /* Create a tempfile and write some text to it.
kono
parents:
diff changeset
3021 .........................0000000001111111.
kono
parents:
diff changeset
3022 .........................1234567890123456. */
kono
parents:
diff changeset
3023 const char *old_content = ("test (int ch)\n" /* line 1. */
kono
parents:
diff changeset
3024 "{\n" /* line 2. */
kono
parents:
diff changeset
3025 " putchar (ch);\n" /* line 3. */
kono
parents:
diff changeset
3026 "}\n"); /* line 4. */
kono
parents:
diff changeset
3027
kono
parents:
diff changeset
3028 temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
kono
parents:
diff changeset
3029 line_table_test ltt (case_);
kono
parents:
diff changeset
3030
kono
parents:
diff changeset
3031 const line_map_ordinary *ord_map = linemap_check_ordinary
kono
parents:
diff changeset
3032 (linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0));
kono
parents:
diff changeset
3033 linemap_line_start (line_table, 1, 100);
kono
parents:
diff changeset
3034
kono
parents:
diff changeset
3035 /* The primary range is the "putchar" token. */
kono
parents:
diff changeset
3036 location_t putchar_start
kono
parents:
diff changeset
3037 = linemap_position_for_line_and_column (line_table, ord_map, 3, 2);
kono
parents:
diff changeset
3038 location_t putchar_finish
kono
parents:
diff changeset
3039 = linemap_position_for_line_and_column (line_table, ord_map, 3, 8);
kono
parents:
diff changeset
3040 location_t putchar_loc
kono
parents:
diff changeset
3041 = make_location (putchar_start, putchar_start, putchar_finish);
kono
parents:
diff changeset
3042 rich_location richloc (line_table, putchar_loc);
kono
parents:
diff changeset
3043
kono
parents:
diff changeset
3044 /* Add a "#include <stdio.h>" on a line by itself at the top of the file. */
kono
parents:
diff changeset
3045 location_t file_start
kono
parents:
diff changeset
3046 = linemap_position_for_line_and_column (line_table, ord_map, 1, 1);
kono
parents:
diff changeset
3047 richloc.add_fixit_insert_before (file_start, "#include <stdio.h>\n");
kono
parents:
diff changeset
3048
kono
parents:
diff changeset
3049 if (putchar_finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
3050 return;
kono
parents:
diff changeset
3051
kono
parents:
diff changeset
3052 test_diagnostic_context dc;
kono
parents:
diff changeset
3053 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
3054 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
3055 "FILENAME:1:1:\n"
kono
parents:
diff changeset
3056 "+#include <stdio.h>\n"
kono
parents:
diff changeset
3057 " test (int ch)\n"
kono
parents:
diff changeset
3058 "FILENAME:3:2:\n"
kono
parents:
diff changeset
3059 " putchar (ch);\n"
kono
parents:
diff changeset
3060 " ^~~~~~~\n",
kono
parents:
diff changeset
3061 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
3062 }
kono
parents:
diff changeset
3063
kono
parents:
diff changeset
3064 /* Replacement fix-it hint containing a newline.
kono
parents:
diff changeset
3065 This will fail, as newlines are only supported when inserting at the
kono
parents:
diff changeset
3066 beginning of a line. */
kono
parents:
diff changeset
3067
kono
parents:
diff changeset
3068 static void
kono
parents:
diff changeset
3069 test_fixit_replace_containing_newline (const line_table_case &case_)
kono
parents:
diff changeset
3070 {
kono
parents:
diff changeset
3071 /* Create a tempfile and write some text to it.
kono
parents:
diff changeset
3072 .........................0000000001111.
kono
parents:
diff changeset
3073 .........................1234567890123. */
kono
parents:
diff changeset
3074 const char *old_content = "foo = bar ();\n";
kono
parents:
diff changeset
3075
kono
parents:
diff changeset
3076 temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
kono
parents:
diff changeset
3077 line_table_test ltt (case_);
kono
parents:
diff changeset
3078 linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
kono
parents:
diff changeset
3079
kono
parents:
diff changeset
3080 /* Replace the " = " with "\n = ", as if we were reformatting an
kono
parents:
diff changeset
3081 overly long line. */
kono
parents:
diff changeset
3082 location_t start = linemap_position_for_column (line_table, 4);
kono
parents:
diff changeset
3083 location_t finish = linemap_position_for_column (line_table, 6);
kono
parents:
diff changeset
3084 location_t loc = linemap_position_for_column (line_table, 13);
kono
parents:
diff changeset
3085 rich_location richloc (line_table, loc);
kono
parents:
diff changeset
3086 source_range range = source_range::from_locations (start, finish);
kono
parents:
diff changeset
3087 richloc.add_fixit_replace (range, "\n =");
kono
parents:
diff changeset
3088
kono
parents:
diff changeset
3089 /* Arbitrary newlines are not yet supported within fix-it hints, so
kono
parents:
diff changeset
3090 the fix-it should not be displayed. */
kono
parents:
diff changeset
3091 ASSERT_TRUE (richloc.seen_impossible_fixit_p ());
kono
parents:
diff changeset
3092
kono
parents:
diff changeset
3093 if (finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
3094 return;
kono
parents:
diff changeset
3095
kono
parents:
diff changeset
3096 test_diagnostic_context dc;
kono
parents:
diff changeset
3097 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
3098 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
3099 " foo = bar ();\n"
kono
parents:
diff changeset
3100 " ^\n",
kono
parents:
diff changeset
3101 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
3102 }
kono
parents:
diff changeset
3103
kono
parents:
diff changeset
3104 /* Fix-it hint, attempting to delete a newline.
kono
parents:
diff changeset
3105 This will fail, as we currently only support fix-it hints that
kono
parents:
diff changeset
3106 affect one line at a time. */
kono
parents:
diff changeset
3107
kono
parents:
diff changeset
3108 static void
kono
parents:
diff changeset
3109 test_fixit_deletion_affecting_newline (const line_table_case &case_)
kono
parents:
diff changeset
3110 {
kono
parents:
diff changeset
3111 /* Create a tempfile and write some text to it.
kono
parents:
diff changeset
3112 ..........................0000000001111.
kono
parents:
diff changeset
3113 ..........................1234567890123. */
kono
parents:
diff changeset
3114 const char *old_content = ("foo = bar (\n"
kono
parents:
diff changeset
3115 " );\n");
kono
parents:
diff changeset
3116
kono
parents:
diff changeset
3117 temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
kono
parents:
diff changeset
3118 line_table_test ltt (case_);
kono
parents:
diff changeset
3119 const line_map_ordinary *ord_map = linemap_check_ordinary
kono
parents:
diff changeset
3120 (linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0));
kono
parents:
diff changeset
3121 linemap_line_start (line_table, 1, 100);
kono
parents:
diff changeset
3122
kono
parents:
diff changeset
3123 /* Attempt to delete the " (\n...)". */
kono
parents:
diff changeset
3124 location_t start
kono
parents:
diff changeset
3125 = linemap_position_for_line_and_column (line_table, ord_map, 1, 10);
kono
parents:
diff changeset
3126 location_t caret
kono
parents:
diff changeset
3127 = linemap_position_for_line_and_column (line_table, ord_map, 1, 11);
kono
parents:
diff changeset
3128 location_t finish
kono
parents:
diff changeset
3129 = linemap_position_for_line_and_column (line_table, ord_map, 2, 7);
kono
parents:
diff changeset
3130 location_t loc = make_location (caret, start, finish);
kono
parents:
diff changeset
3131 rich_location richloc (line_table, loc);
kono
parents:
diff changeset
3132 richloc. add_fixit_remove ();
kono
parents:
diff changeset
3133
kono
parents:
diff changeset
3134 /* Fix-it hints that affect more than one line are not yet supported, so
kono
parents:
diff changeset
3135 the fix-it should not be displayed. */
kono
parents:
diff changeset
3136 ASSERT_TRUE (richloc.seen_impossible_fixit_p ());
kono
parents:
diff changeset
3137
kono
parents:
diff changeset
3138 if (finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
kono
parents:
diff changeset
3139 return;
kono
parents:
diff changeset
3140
kono
parents:
diff changeset
3141 test_diagnostic_context dc;
kono
parents:
diff changeset
3142 diagnostic_show_locus (&dc, &richloc, DK_ERROR);
kono
parents:
diff changeset
3143 ASSERT_STREQ ("\n"
kono
parents:
diff changeset
3144 " foo = bar (\n"
kono
parents:
diff changeset
3145 " ~^\n"
kono
parents:
diff changeset
3146 " );\n"
kono
parents:
diff changeset
3147 " ~ \n",
kono
parents:
diff changeset
3148 pp_formatted_text (dc.printer));
kono
parents:
diff changeset
3149 }
kono
parents:
diff changeset
3150
kono
parents:
diff changeset
3151 /* Run all of the selftests within this file. */
kono
parents:
diff changeset
3152
kono
parents:
diff changeset
3153 void
kono
parents:
diff changeset
3154 diagnostic_show_locus_c_tests ()
kono
parents:
diff changeset
3155 {
kono
parents:
diff changeset
3156 test_layout_range_for_single_point ();
kono
parents:
diff changeset
3157 test_layout_range_for_single_line ();
kono
parents:
diff changeset
3158 test_layout_range_for_multiple_lines ();
kono
parents:
diff changeset
3159
kono
parents:
diff changeset
3160 test_get_line_width_without_trailing_whitespace ();
kono
parents:
diff changeset
3161
kono
parents:
diff changeset
3162 test_diagnostic_show_locus_unknown_location ();
kono
parents:
diff changeset
3163
kono
parents:
diff changeset
3164 for_each_line_table_case (test_diagnostic_show_locus_one_liner);
kono
parents:
diff changeset
3165 for_each_line_table_case (test_add_location_if_nearby);
kono
parents:
diff changeset
3166 for_each_line_table_case (test_diagnostic_show_locus_fixit_lines);
kono
parents:
diff changeset
3167 for_each_line_table_case (test_fixit_consolidation);
kono
parents:
diff changeset
3168 for_each_line_table_case (test_overlapped_fixit_printing);
kono
parents:
diff changeset
3169 for_each_line_table_case (test_overlapped_fixit_printing_2);
kono
parents:
diff changeset
3170 for_each_line_table_case (test_fixit_insert_containing_newline);
kono
parents:
diff changeset
3171 for_each_line_table_case (test_fixit_insert_containing_newline_2);
kono
parents:
diff changeset
3172 for_each_line_table_case (test_fixit_replace_containing_newline);
kono
parents:
diff changeset
3173 for_each_line_table_case (test_fixit_deletion_affecting_newline);
kono
parents:
diff changeset
3174 }
kono
parents:
diff changeset
3175
kono
parents:
diff changeset
3176 } // namespace selftest
kono
parents:
diff changeset
3177
kono
parents:
diff changeset
3178 #endif /* #if CHECKING_P */