Branch data Line data Source code
1 : : /* Bundles of location information used when printing diagnostics.
2 : : Copyright (C) 2015-2024 Free Software Foundation, Inc.
3 : :
4 : : This program is free software; you can redistribute it and/or modify it
5 : : under the terms of the GNU General Public License as published by the
6 : : Free Software Foundation; either version 3, or (at your option) any
7 : : later version.
8 : :
9 : : This program is distributed in the hope that it will be useful,
10 : : but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : : GNU General Public License for more details.
13 : :
14 : : You should have received a copy of the GNU General Public License
15 : : along with this program; see the file COPYING3. If not see
16 : : <http://www.gnu.org/licenses/>.
17 : :
18 : : In other words, you are welcome to use, share and improve this program.
19 : : You are forbidden to forbid anyone else to use, share and improve
20 : : what you give them. Help stamp out software-hoarding! */
21 : :
22 : : #ifndef LIBCPP_RICH_LOCATION_H
23 : : #define LIBCPP_RICH_LOCATION_H
24 : :
25 : : class range_label;
26 : :
27 : : /* A hint to diagnostic_show_locus on how to print a source range within a
28 : : rich_location.
29 : :
30 : : Typically this is SHOW_RANGE_WITH_CARET for the 0th range, and
31 : : SHOW_RANGE_WITHOUT_CARET for subsequent ranges,
32 : : but the Fortran frontend uses SHOW_RANGE_WITH_CARET repeatedly for
33 : : printing things like:
34 : :
35 : : x = x + y
36 : : 1 2
37 : : Error: Shapes for operands at (1) and (2) are not conformable
38 : :
39 : : where "1" and "2" are notionally carets. */
40 : :
41 : : enum range_display_kind
42 : : {
43 : : /* Show the pertinent source line(s), the caret, and underline(s). */
44 : : SHOW_RANGE_WITH_CARET,
45 : :
46 : : /* Show the pertinent source line(s) and underline(s), but don't
47 : : show the caret (just an underline). */
48 : : SHOW_RANGE_WITHOUT_CARET,
49 : :
50 : : /* Just show the source lines; don't show the range itself.
51 : : This is for use when displaying some line-insertion fix-it hints (for
52 : : showing the user context on the change, for when it doesn't make sense
53 : : to highlight the first column on the next line). */
54 : : SHOW_LINES_WITHOUT_RANGE
55 : : };
56 : :
57 : : /* A location within a rich_location: a caret&range, with
58 : : the caret potentially flagged for display, and an optional
59 : : label. */
60 : :
61 : : struct location_range
62 : : {
63 : : location_t m_loc;
64 : :
65 : : enum range_display_kind m_range_display_kind;
66 : :
67 : : /* If non-NULL, the label for this range. */
68 : : const range_label *m_label;
69 : : };
70 : :
71 : : /* A partially-embedded vec for use within rich_location for storing
72 : : ranges and fix-it hints.
73 : :
74 : : Elements [0..NUM_EMBEDDED) are allocated within m_embed, after
75 : : that they are within the dynamically-allocated m_extra.
76 : :
77 : : This allows for static allocation in the common case, whilst
78 : : supporting the rarer case of an arbitrary number of elements.
79 : :
80 : : Dynamic allocation is not performed unless it's needed. */
81 : :
82 : : template <typename T, int NUM_EMBEDDED>
83 : : class semi_embedded_vec
84 : : {
85 : : public:
86 : : semi_embedded_vec ();
87 : : ~semi_embedded_vec ();
88 : :
89 : 1793306 : unsigned int count () const { return m_num; }
90 : : T& operator[] (int idx);
91 : : const T& operator[] (int idx) const;
92 : :
93 : : void push (const T&);
94 : : void truncate (int len);
95 : :
96 : : private:
97 : : int m_num;
98 : : T m_embedded[NUM_EMBEDDED];
99 : : int m_alloc;
100 : : T *m_extra;
101 : : };
102 : :
103 : : /* Constructor for semi_embedded_vec. In particular, no dynamic allocation
104 : : is done. */
105 : :
106 : : template <typename T, int NUM_EMBEDDED>
107 : : semi_embedded_vec<T, NUM_EMBEDDED>::semi_embedded_vec ()
108 : : : m_num (0), m_alloc (0), m_extra (NULL)
109 : : {
110 : : }
111 : :
112 : : /* semi_embedded_vec's dtor. Release any dynamically-allocated memory. */
113 : :
114 : : template <typename T, int NUM_EMBEDDED>
115 : : semi_embedded_vec<T, NUM_EMBEDDED>::~semi_embedded_vec ()
116 : : {
117 : : XDELETEVEC (m_extra);
118 : : }
119 : :
120 : : /* Look up element IDX, mutably. */
121 : :
122 : : template <typename T, int NUM_EMBEDDED>
123 : : T&
124 : : semi_embedded_vec<T, NUM_EMBEDDED>::operator[] (int idx)
125 : : {
126 : : linemap_assert (idx < m_num);
127 : : if (idx < NUM_EMBEDDED)
128 : : return m_embedded[idx];
129 : : else
130 : : {
131 : : linemap_assert (m_extra != NULL);
132 : : return m_extra[idx - NUM_EMBEDDED];
133 : : }
134 : : }
135 : :
136 : : /* Look up element IDX (const). */
137 : :
138 : : template <typename T, int NUM_EMBEDDED>
139 : : const T&
140 : 34275 : semi_embedded_vec<T, NUM_EMBEDDED>::operator[] (int idx) const
141 : : {
142 : 34275 : linemap_assert (idx < m_num);
143 : 34275 : if (idx < NUM_EMBEDDED)
144 : 31033 : return m_embedded[idx];
145 : : else
146 : : {
147 : 3242 : linemap_assert (m_extra != NULL);
148 : 3242 : return m_extra[idx - NUM_EMBEDDED];
149 : : }
150 : : }
151 : :
152 : : /* Append VALUE to the end of the semi_embedded_vec. */
153 : :
154 : : template <typename T, int NUM_EMBEDDED>
155 : : void
156 : : semi_embedded_vec<T, NUM_EMBEDDED>::push (const T& value)
157 : : {
158 : : int idx = m_num++;
159 : : if (idx < NUM_EMBEDDED)
160 : : m_embedded[idx] = value;
161 : : else
162 : : {
163 : : /* Offset "idx" to be an index within m_extra. */
164 : : idx -= NUM_EMBEDDED;
165 : : if (NULL == m_extra)
166 : : {
167 : : linemap_assert (m_alloc == 0);
168 : : m_alloc = 16;
169 : : m_extra = XNEWVEC (T, m_alloc);
170 : : }
171 : : else if (idx >= m_alloc)
172 : : {
173 : : linemap_assert (m_alloc > 0);
174 : : m_alloc *= 2;
175 : : m_extra = XRESIZEVEC (T, m_extra, m_alloc);
176 : : }
177 : : linemap_assert (m_extra);
178 : : linemap_assert (idx < m_alloc);
179 : : m_extra[idx] = value;
180 : : }
181 : : }
182 : :
183 : : /* Truncate to length LEN. No deallocation is performed. */
184 : :
185 : : template <typename T, int NUM_EMBEDDED>
186 : : void
187 : : semi_embedded_vec<T, NUM_EMBEDDED>::truncate (int len)
188 : : {
189 : : linemap_assert (len <= m_num);
190 : : m_num = len;
191 : : }
192 : :
193 : : class fixit_hint;
194 : : class diagnostic_path;
195 : :
196 : : /* A "rich" source code location, for use when printing diagnostics.
197 : : A rich_location has one or more carets&ranges, where the carets
198 : : are optional. These are referred to as "ranges" from here.
199 : : Typically the zeroth range has a caret; other ranges sometimes
200 : : have carets.
201 : :
202 : : The "primary" location of a rich_location is the caret of range 0,
203 : : used for determining the line/column when printing diagnostic
204 : : text, such as:
205 : :
206 : : some-file.c:3:1: error: ...etc...
207 : :
208 : : Additional ranges may be added to help the user identify other
209 : : pertinent clauses in a diagnostic.
210 : :
211 : : Ranges can (optionally) be given labels via class range_label.
212 : :
213 : : rich_location instances are intended to be allocated on the stack
214 : : when generating diagnostics, and to be short-lived.
215 : :
216 : : Examples of rich locations
217 : : --------------------------
218 : :
219 : : Example A
220 : : *********
221 : : int i = "foo";
222 : : ^
223 : : This "rich" location is simply a single range (range 0), with
224 : : caret = start = finish at the given point.
225 : :
226 : : Example B
227 : : *********
228 : : a = (foo && bar)
229 : : ~~~~~^~~~~~~
230 : : This rich location has a single range (range 0), with the caret
231 : : at the first "&", and the start/finish at the parentheses.
232 : : Compare with example C below.
233 : :
234 : : Example C
235 : : *********
236 : : a = (foo && bar)
237 : : ~~~ ^~ ~~~
238 : : This rich location has three ranges:
239 : : - Range 0 has its caret and start location at the first "&" and
240 : : end at the second "&.
241 : : - Range 1 has its start and finish at the "f" and "o" of "foo";
242 : : the caret is not flagged for display, but is perhaps at the "f"
243 : : of "foo".
244 : : - Similarly, range 2 has its start and finish at the "b" and "r" of
245 : : "bar"; the caret is not flagged for display, but is perhaps at the
246 : : "b" of "bar".
247 : : Compare with example B above.
248 : :
249 : : Example D (Fortran frontend)
250 : : ****************************
251 : : x = x + y
252 : : 1 2
253 : : This rich location has range 0 at "1", and range 1 at "2".
254 : : Both are flagged for caret display. Both ranges have start/finish
255 : : equal to their caret point. The frontend overrides the diagnostic
256 : : context's default caret character for these ranges.
257 : :
258 : : Example E (range labels)
259 : : ************************
260 : : printf ("arg0: %i arg1: %s arg2: %i",
261 : : ^~
262 : : |
263 : : const char *
264 : : 100, 101, 102);
265 : : ~~~
266 : : |
267 : : int
268 : : This rich location has two ranges:
269 : : - range 0 is at the "%s" with start = caret = "%" and finish at
270 : : the "s". It has a range_label ("const char *").
271 : : - range 1 has start/finish covering the "101" and is not flagged for
272 : : caret printing. The caret is at the start of "101", where its
273 : : range_label is printed ("int").
274 : :
275 : : Fix-it hints
276 : : ------------
277 : :
278 : : Rich locations can also contain "fix-it hints", giving suggestions
279 : : for the user on how to edit their code to fix a problem. These
280 : : can be expressed as insertions, replacements, and removals of text.
281 : : The edits by default are relative to the zeroth range within the
282 : : rich_location, but optionally they can be expressed relative to
283 : : other locations (using various overloaded methods of the form
284 : : rich_location::add_fixit_*).
285 : :
286 : : For example:
287 : :
288 : : Example F: fix-it hint: insert_before
289 : : *************************************
290 : : ptr = arr[0];
291 : : ^~~~~~
292 : : &
293 : : This rich location has a single range (range 0) covering "arr[0]",
294 : : with the caret at the start. The rich location has a single
295 : : insertion fix-it hint, inserted before range 0, added via
296 : : richloc.add_fixit_insert_before ("&");
297 : :
298 : : Example G: multiple fix-it hints: insert_before and insert_after
299 : : ****************************************************************
300 : : #define FN(ARG0, ARG1, ARG2) fn(ARG0, ARG1, ARG2)
301 : : ^~~~ ^~~~ ^~~~
302 : : ( ) ( ) ( )
303 : : This rich location has three ranges, covering "arg0", "arg1",
304 : : and "arg2", all with caret-printing enabled.
305 : : The rich location has 6 insertion fix-it hints: each arg
306 : : has a pair of insertion fix-it hints, suggesting wrapping
307 : : them with parentheses: one a '(' inserted before,
308 : : the other a ')' inserted after, added via
309 : : richloc.add_fixit_insert_before (LOC, "(");
310 : : and
311 : : richloc.add_fixit_insert_after (LOC, ")");
312 : :
313 : : Example H: fix-it hint: removal
314 : : *******************************
315 : : struct s {int i};;
316 : : ^
317 : : -
318 : : This rich location has a single range at the stray trailing
319 : : semicolon, along with a single removal fix-it hint, covering
320 : : the same range, added via:
321 : : richloc.add_fixit_remove ();
322 : :
323 : : Example I: fix-it hint: replace
324 : : *******************************
325 : : c = s.colour;
326 : : ^~~~~~
327 : : color
328 : : This rich location has a single range (range 0) covering "colour",
329 : : and a single "replace" fix-it hint, covering the same range,
330 : : added via
331 : : richloc.add_fixit_replace ("color");
332 : :
333 : : Example J: fix-it hint: line insertion
334 : : **************************************
335 : :
336 : : 3 | #include <stddef.h>
337 : : + |+#include <stdio.h>
338 : : 4 | int the_next_line;
339 : :
340 : : This rich location has a single range at line 4 column 1, marked
341 : : with SHOW_LINES_WITHOUT_RANGE (to avoid printing a meaningless caret
342 : : on the "i" of int). It has a insertion fix-it hint of the string
343 : : "#include <stdio.h>\n".
344 : :
345 : : Adding a fix-it hint can fail: for example, attempts to insert content
346 : : at the transition between two line maps may fail due to there being no
347 : : location_t value to express the new location.
348 : :
349 : : Attempts to add a fix-it hint within a macro expansion will fail.
350 : :
351 : : There is only limited support for newline characters in fix-it hints:
352 : : only hints with newlines which insert an entire new line are permitted,
353 : : inserting at the start of a line, and finishing with a newline
354 : : (with no interior newline characters). Other attempts to add
355 : : fix-it hints containing newline characters will fail.
356 : : Similarly, attempts to delete or replace a range *affecting* multiple
357 : : lines will fail.
358 : :
359 : : The rich_location API handles these failures gracefully, so that
360 : : diagnostics can attempt to add fix-it hints without each needing
361 : : extensive checking.
362 : :
363 : : Fix-it hints within a rich_location are "atomic": if any hints can't
364 : : be applied, none of them will be (tracked by the m_seen_impossible_fixit
365 : : flag), and no fix-its hints will be displayed for that rich_location.
366 : : This implies that diagnostic messages need to be worded in such a way
367 : : that they make sense whether or not the fix-it hints are displayed,
368 : : or that richloc.seen_impossible_fixit_p () should be checked before
369 : : issuing the diagnostics. */
370 : :
371 : : class rich_location
372 : : {
373 : : public:
374 : : /* Constructors. */
375 : :
376 : : /* Constructing from a location. */
377 : : rich_location (line_maps *set, location_t loc,
378 : : const range_label *label = NULL);
379 : :
380 : : /* Destructor. */
381 : : ~rich_location ();
382 : :
383 : : /* The class manages the memory pointed to by the elements of
384 : : the M_FIXIT_HINTS vector and is not meant to be copied or
385 : : assigned. */
386 : : rich_location (const rich_location &) = delete;
387 : : void operator= (const rich_location &) = delete;
388 : :
389 : : /* Accessors. */
390 : 88711045 : location_t get_loc () const { return get_loc (0); }
391 : : location_t get_loc (unsigned int idx) const;
392 : :
393 : : void
394 : : add_range (location_t loc,
395 : : enum range_display_kind range_display_kind
396 : : = SHOW_RANGE_WITHOUT_CARET,
397 : : const range_label *label = NULL);
398 : :
399 : : void
400 : : set_range (unsigned int idx, location_t loc,
401 : : enum range_display_kind range_display_kind);
402 : :
403 : 1525685 : unsigned int get_num_locations () const { return m_ranges.count (); }
404 : :
405 : : const location_range *get_range (unsigned int idx) const;
406 : : location_range *get_range (unsigned int idx);
407 : :
408 : : expanded_location get_expanded_location (unsigned int idx) const;
409 : :
410 : : void
411 : : override_column (int column);
412 : :
413 : : /* Fix-it hints. */
414 : :
415 : : /* Methods for adding insertion fix-it hints. */
416 : :
417 : : /* Suggest inserting NEW_CONTENT immediately before the primary
418 : : range's start. */
419 : : void
420 : : add_fixit_insert_before (const char *new_content);
421 : :
422 : : /* Suggest inserting NEW_CONTENT immediately before the start of WHERE. */
423 : : void
424 : : add_fixit_insert_before (location_t where,
425 : : const char *new_content);
426 : :
427 : : /* Suggest inserting NEW_CONTENT immediately after the end of the primary
428 : : range. */
429 : : void
430 : : add_fixit_insert_after (const char *new_content);
431 : :
432 : : /* Suggest inserting NEW_CONTENT immediately after the end of WHERE. */
433 : : void
434 : : add_fixit_insert_after (location_t where,
435 : : const char *new_content);
436 : :
437 : : /* Methods for adding removal fix-it hints. */
438 : :
439 : : /* Suggest removing the content covered by range 0. */
440 : : void
441 : : add_fixit_remove ();
442 : :
443 : : /* Suggest removing the content covered between the start and finish
444 : : of WHERE. */
445 : : void
446 : : add_fixit_remove (location_t where);
447 : :
448 : : /* Suggest removing the content covered by SRC_RANGE. */
449 : : void
450 : : add_fixit_remove (source_range src_range);
451 : :
452 : : /* Methods for adding "replace" fix-it hints. */
453 : :
454 : : /* Suggest replacing the content covered by range 0 with NEW_CONTENT. */
455 : : void
456 : : add_fixit_replace (const char *new_content);
457 : :
458 : : /* Suggest replacing the content between the start and finish of
459 : : WHERE with NEW_CONTENT. */
460 : : void
461 : : add_fixit_replace (location_t where,
462 : : const char *new_content);
463 : :
464 : : /* Suggest replacing the content covered by SRC_RANGE with
465 : : NEW_CONTENT. */
466 : : void
467 : : add_fixit_replace (source_range src_range,
468 : : const char *new_content);
469 : :
470 : 267621 : unsigned int get_num_fixit_hints () const { return m_fixit_hints.count (); }
471 : 34275 : fixit_hint *get_fixit_hint (int idx) const { return m_fixit_hints[idx]; }
472 : : fixit_hint *get_last_fixit_hint () const;
473 : 76882 : bool seen_impossible_fixit_p () const { return m_seen_impossible_fixit; }
474 : :
475 : : /* Set this if the fix-it hints are not suitable to be
476 : : automatically applied.
477 : :
478 : : For example, if you are suggesting more than one
479 : : mutually exclusive solution to a problem, then
480 : : it doesn't make sense to apply all of the solutions;
481 : : manual intervention is required.
482 : :
483 : : If set, then the fix-it hints in the rich_location will
484 : : be printed, but will not be added to generated patches,
485 : : or affect the modified version of the file. */
486 : 176 : void fixits_cannot_be_auto_applied ()
487 : : {
488 : 176 : m_fixits_cannot_be_auto_applied = true;
489 : : }
490 : :
491 : 71 : bool fixits_can_be_auto_applied_p () const
492 : : {
493 : 71 : return !m_fixits_cannot_be_auto_applied;
494 : : }
495 : :
496 : : /* An optional path through the code. */
497 : 1390575 : const diagnostic_path *get_path () const { return m_path; }
498 : 4511 : void set_path (const diagnostic_path *path) { m_path = path; }
499 : :
500 : : /* A flag for hinting that the diagnostic involves character encoding
501 : : issues, and thus that it will be helpful to the user if we show some
502 : : representation of how the characters in the pertinent source lines
503 : : are encoded.
504 : : The default is false (i.e. do not escape).
505 : : When set to true, non-ASCII bytes in the pertinent source lines will
506 : : be escaped in a manner controlled by the user-supplied option
507 : : -fdiagnostics-escape-format=, so that the user can better understand
508 : : what's going on with the encoding in their source file. */
509 : 217863 : bool escape_on_output_p () const { return m_escape_on_output; }
510 : 206 : void set_escape_on_output (bool flag) { m_escape_on_output = flag; }
511 : :
512 : 108803 : const line_maps *get_line_table () const { return m_line_table; }
513 : :
514 : : private:
515 : : bool reject_impossible_fixit (location_t where);
516 : : void stop_supporting_fixits ();
517 : : void maybe_add_fixit (location_t start,
518 : : location_t next_loc,
519 : : const char *new_content);
520 : :
521 : : public:
522 : : static const int STATICALLY_ALLOCATED_RANGES = 3;
523 : :
524 : : protected:
525 : : line_maps * const m_line_table;
526 : : semi_embedded_vec <location_range, STATICALLY_ALLOCATED_RANGES> m_ranges;
527 : :
528 : : int m_column_override;
529 : :
530 : : mutable bool m_have_expanded_location;
531 : : bool m_seen_impossible_fixit;
532 : : bool m_fixits_cannot_be_auto_applied;
533 : : bool m_escape_on_output;
534 : :
535 : : mutable expanded_location m_expanded_location;
536 : :
537 : : static const int MAX_STATIC_FIXIT_HINTS = 2;
538 : : semi_embedded_vec <fixit_hint *, MAX_STATIC_FIXIT_HINTS> m_fixit_hints;
539 : :
540 : : const diagnostic_path *m_path;
541 : : };
542 : :
543 : : /* A struct for the result of range_label::get_text: a NUL-terminated buffer
544 : : of localized text, and a flag to determine if the caller should "free" the
545 : : buffer. */
546 : :
547 : : class label_text
548 : : {
549 : : public:
550 : 14596 : label_text ()
551 : 13853 : : m_buffer (NULL), m_owned (false)
552 : 213 : {}
553 : :
554 : 419796 : ~label_text ()
555 : : {
556 : 414437 : if (m_owned)
557 : 365587 : free (m_buffer);
558 : 106 : }
559 : :
560 : : /* Move ctor. */
561 : 19129 : label_text (label_text &&other)
562 : 19129 : : m_buffer (other.m_buffer), m_owned (other.m_owned)
563 : : {
564 : 19129 : other.release ();
565 : 13515 : }
566 : :
567 : : /* Move assignment. */
568 : 5425 : label_text & operator= (label_text &&other)
569 : : {
570 : 5425 : if (m_owned)
571 : 0 : free (m_buffer);
572 : 5425 : m_buffer = other.m_buffer;
573 : 5425 : m_owned = other.m_owned;
574 : 5425 : other.release ();
575 : 5425 : return *this;
576 : : }
577 : :
578 : : /* Delete the copy ctor and copy-assignment operator. */
579 : : label_text (const label_text &) = delete;
580 : : label_text & operator= (const label_text &) = delete;
581 : :
582 : : /* Create a label_text instance that borrows BUFFER from a
583 : : longer-lived owner. */
584 : 27066 : static label_text borrow (const char *buffer)
585 : : {
586 : 27066 : return label_text (const_cast <char *> (buffer), false);
587 : : }
588 : :
589 : : /* Create a label_text instance that takes ownership of BUFFER. */
590 : 367658 : static label_text take (char *buffer)
591 : : {
592 : 367658 : return label_text (buffer, true);
593 : : }
594 : :
595 : 29641 : void release ()
596 : : {
597 : 29641 : m_buffer = NULL;
598 : 24490 : m_owned = false;
599 : : }
600 : :
601 : 405232 : const char *get () const
602 : : {
603 : 391733 : return m_buffer;
604 : : }
605 : :
606 : 5087 : bool is_owner () const
607 : : {
608 : 5087 : return m_owned;
609 : : }
610 : :
611 : : private:
612 : : char *m_buffer;
613 : : bool m_owned;
614 : :
615 : 394724 : label_text (char *buffer, bool owned)
616 : 393979 : : m_buffer (buffer), m_owned (owned)
617 : : {}
618 : : };
619 : :
620 : : /* Abstract base class for labelling a range within a rich_location
621 : : (e.g. for labelling expressions with their type).
622 : :
623 : : Generating the text could require non-trivial work, so this work
624 : : is delayed (via the "get_text" virtual function) until the diagnostic
625 : : printing code "knows" it needs it, thus avoiding doing it e.g. for
626 : : warnings that are filtered by command-line flags. This virtual
627 : : function also isolates libcpp and the diagnostics subsystem from
628 : : the front-end and middle-end-specific code for generating the text
629 : : for the labels.
630 : :
631 : : Like the rich_location instances they annotate, range_label instances
632 : : are intended to be allocated on the stack when generating diagnostics,
633 : : and to be short-lived. */
634 : :
635 : 8857 : class range_label
636 : : {
637 : : public:
638 : 7509 : virtual ~range_label () {}
639 : :
640 : : /* Get localized text for the label.
641 : : The RANGE_IDX is provided, allowing for range_label instances to be
642 : : shared by multiple ranges if need be (the "flyweight" design pattern). */
643 : : virtual label_text get_text (unsigned range_idx) const = 0;
644 : : };
645 : :
646 : : /* A fix-it hint: a suggested insertion, replacement, or deletion of text.
647 : : We handle these three types of edit with one class, by representing
648 : : them as replacement of a half-open range:
649 : : [start, next_loc)
650 : : Insertions have start == next_loc: "replace" the empty string at the
651 : : start location with the new string.
652 : : Deletions are replacement with the empty string.
653 : :
654 : : There is only limited support for newline characters in fix-it hints
655 : : as noted above in the comment for class rich_location.
656 : : A fixit_hint instance can have at most one newline character; if
657 : : present, the newline character must be the final character of
658 : : the content (preventing e.g. fix-its that split a pre-existing line). */
659 : :
660 : : class fixit_hint
661 : : {
662 : : public:
663 : : fixit_hint (location_t start,
664 : : location_t next_loc,
665 : : const char *new_content);
666 : : ~fixit_hint () { free (m_bytes); }
667 : :
668 : : bool affects_line_p (const line_maps *set,
669 : : const char *file,
670 : : int line) const;
671 : 114281 : location_t get_start_loc () const { return m_start; }
672 : 92598 : location_t get_next_loc () const { return m_next_loc; }
673 : : bool maybe_append (location_t start,
674 : : location_t next_loc,
675 : : const char *new_content);
676 : :
677 : 21149 : const char *get_string () const { return m_bytes; }
678 : 59085 : size_t get_length () const { return m_len; }
679 : :
680 : 38977 : bool insertion_p () const { return m_start == m_next_loc; }
681 : :
682 : : bool ends_with_newline_p () const;
683 : :
684 : : private:
685 : : /* We don't use source_range here since, unlike most places,
686 : : this is a half-open/half-closed range:
687 : : [start, next_loc)
688 : : so that we can support insertion via start == next_loc. */
689 : : location_t m_start;
690 : : location_t m_next_loc;
691 : : char *m_bytes;
692 : : size_t m_len;
693 : : };
694 : :
695 : : #endif /* !LIBCPP_RICH_LOCATION_H */
|