1 /* Bundles of location information used when printing diagnostics.
2 Copyright (C) 2015-2023 Free Software Foundation, Inc.
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
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.
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/>.
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! */
22 #ifndef LIBCPP_RICH_LOCATION_H
23 #define LIBCPP_RICH_LOCATION_H
27 /* A hint to diagnostic_show_locus on how to print a source range within a
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
37 Error: Shapes for operands at (1) and (2) are not conformable
39 where "1" and "2" are notionally carets. */
41 enum range_display_kind
43 /* Show the pertinent source line(s), the caret, and underline(s). */
44 SHOW_RANGE_WITH_CARET
,
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
,
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
57 /* A location within a rich_location: a caret&range, with
58 the caret potentially flagged for display, and an optional
65 enum range_display_kind m_range_display_kind
;
67 /* If non-NULL, the label for this range. */
68 const range_label
*m_label
;
71 /* A partially-embedded vec for use within rich_location for storing
72 ranges and fix-it hints.
74 Elements [0..NUM_EMBEDDED) are allocated within m_embed, after
75 that they are within the dynamically-allocated m_extra.
77 This allows for static allocation in the common case, whilst
78 supporting the rarer case of an arbitrary number of elements.
80 Dynamic allocation is not performed unless it's needed. */
82 template <typename T
, int NUM_EMBEDDED
>
83 class semi_embedded_vec
87 ~semi_embedded_vec ();
89 unsigned int count () const { return m_num
; }
90 T
& operator[] (int idx
);
91 const T
& operator[] (int idx
) const;
94 void truncate (int len
);
98 T m_embedded
[NUM_EMBEDDED
];
103 /* Constructor for semi_embedded_vec. In particular, no dynamic allocation
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
)
112 /* semi_embedded_vec's dtor. Release any dynamically-allocated memory. */
114 template <typename T
, int NUM_EMBEDDED
>
115 semi_embedded_vec
<T
, NUM_EMBEDDED
>::~semi_embedded_vec ()
117 XDELETEVEC (m_extra
);
120 /* Look up element IDX, mutably. */
122 template <typename T
, int NUM_EMBEDDED
>
124 semi_embedded_vec
<T
, NUM_EMBEDDED
>::operator[] (int idx
)
126 linemap_assert (idx
< m_num
);
127 if (idx
< NUM_EMBEDDED
)
128 return m_embedded
[idx
];
131 linemap_assert (m_extra
!= NULL
);
132 return m_extra
[idx
- NUM_EMBEDDED
];
136 /* Look up element IDX (const). */
138 template <typename T
, int NUM_EMBEDDED
>
140 semi_embedded_vec
<T
, NUM_EMBEDDED
>::operator[] (int idx
) const
142 linemap_assert (idx
< m_num
);
143 if (idx
< NUM_EMBEDDED
)
144 return m_embedded
[idx
];
147 linemap_assert (m_extra
!= NULL
);
148 return m_extra
[idx
- NUM_EMBEDDED
];
152 /* Append VALUE to the end of the semi_embedded_vec. */
154 template <typename T
, int NUM_EMBEDDED
>
156 semi_embedded_vec
<T
, NUM_EMBEDDED
>::push (const T
& value
)
159 if (idx
< NUM_EMBEDDED
)
160 m_embedded
[idx
] = value
;
163 /* Offset "idx" to be an index within m_extra. */
167 linemap_assert (m_alloc
== 0);
169 m_extra
= XNEWVEC (T
, m_alloc
);
171 else if (idx
>= m_alloc
)
173 linemap_assert (m_alloc
> 0);
175 m_extra
= XRESIZEVEC (T
, m_extra
, m_alloc
);
177 linemap_assert (m_extra
);
178 linemap_assert (idx
< m_alloc
);
179 m_extra
[idx
] = value
;
183 /* Truncate to length LEN. No deallocation is performed. */
185 template <typename T
, int NUM_EMBEDDED
>
187 semi_embedded_vec
<T
, NUM_EMBEDDED
>::truncate (int len
)
189 linemap_assert (len
<= m_num
);
194 class diagnostic_path
;
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
202 The "primary" location of a rich_location is the caret of range 0,
203 used for determining the line/column when printing diagnostic
206 some-file.c:3:1: error: ...etc...
208 Additional ranges may be added to help the user identify other
209 pertinent clauses in a diagnostic.
211 Ranges can (optionally) be given labels via class range_label.
213 rich_location instances are intended to be allocated on the stack
214 when generating diagnostics, and to be short-lived.
216 Examples of rich locations
217 --------------------------
223 This "rich" location is simply a single range (range 0), with
224 caret = start = finish at the given point.
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.
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"
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
247 Compare with example B above.
249 Example D (Fortran frontend)
250 ****************************
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.
258 Example E (range labels)
259 ************************
260 printf ("arg0: %i arg1: %s arg2: %i",
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").
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_*).
288 Example F: fix-it hint: insert_before
289 *************************************
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 ("&");
298 Example G: multiple fix-it hints: insert_before and insert_after
299 ****************************************************************
300 #define FN(ARG0, ARG1, ARG2) fn(ARG0, ARG1, ARG2)
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, "(");
311 richloc.add_fixit_insert_after (LOC, ")");
313 Example H: fix-it hint: removal
314 *******************************
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 ();
323 Example I: fix-it hint: replace
324 *******************************
328 This rich location has a single range (range 0) covering "colour",
329 and a single "replace" fix-it hint, covering the same range,
331 richloc.add_fixit_replace ("color");
333 Example J: fix-it hint: line insertion
334 **************************************
336 3 | #include <stddef.h>
337 + |+#include <stdio.h>
338 4 | int the_next_line;
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".
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.
349 Attempts to add a fix-it hint within a macro expansion will fail.
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
359 The rich_location API handles these failures gracefully, so that
360 diagnostics can attempt to add fix-it hints without each needing
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. */
376 /* Constructing from a location. */
377 rich_location (line_maps
*set
, location_t loc
,
378 const range_label
*label
= NULL
);
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
386 rich_location (const rich_location
&) = delete;
387 void operator= (const rich_location
&) = delete;
390 location_t
get_loc () const { return get_loc (0); }
391 location_t
get_loc (unsigned int idx
) const;
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
);
400 set_range (unsigned int idx
, location_t loc
,
401 enum range_display_kind range_display_kind
);
403 unsigned int get_num_locations () const { return m_ranges
.count (); }
405 const location_range
*get_range (unsigned int idx
) const;
406 location_range
*get_range (unsigned int idx
);
408 expanded_location
get_expanded_location (unsigned int idx
) const;
411 override_column (int column
);
415 /* Methods for adding insertion fix-it hints. */
417 /* Suggest inserting NEW_CONTENT immediately before the primary
420 add_fixit_insert_before (const char *new_content
);
422 /* Suggest inserting NEW_CONTENT immediately before the start of WHERE. */
424 add_fixit_insert_before (location_t where
,
425 const char *new_content
);
427 /* Suggest inserting NEW_CONTENT immediately after the end of the primary
430 add_fixit_insert_after (const char *new_content
);
432 /* Suggest inserting NEW_CONTENT immediately after the end of WHERE. */
434 add_fixit_insert_after (location_t where
,
435 const char *new_content
);
437 /* Methods for adding removal fix-it hints. */
439 /* Suggest removing the content covered by range 0. */
443 /* Suggest removing the content covered between the start and finish
446 add_fixit_remove (location_t where
);
448 /* Suggest removing the content covered by SRC_RANGE. */
450 add_fixit_remove (source_range src_range
);
452 /* Methods for adding "replace" fix-it hints. */
454 /* Suggest replacing the content covered by range 0 with NEW_CONTENT. */
456 add_fixit_replace (const char *new_content
);
458 /* Suggest replacing the content between the start and finish of
459 WHERE with NEW_CONTENT. */
461 add_fixit_replace (location_t where
,
462 const char *new_content
);
464 /* Suggest replacing the content covered by SRC_RANGE with
467 add_fixit_replace (source_range src_range
,
468 const char *new_content
);
470 unsigned int get_num_fixit_hints () const { return m_fixit_hints
.count (); }
471 fixit_hint
*get_fixit_hint (int idx
) const { return m_fixit_hints
[idx
]; }
472 fixit_hint
*get_last_fixit_hint () const;
473 bool seen_impossible_fixit_p () const { return m_seen_impossible_fixit
; }
475 /* Set this if the fix-it hints are not suitable to be
476 automatically applied.
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.
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 void fixits_cannot_be_auto_applied ()
488 m_fixits_cannot_be_auto_applied
= true;
491 bool fixits_can_be_auto_applied_p () const
493 return !m_fixits_cannot_be_auto_applied
;
496 /* An optional path through the code. */
497 const diagnostic_path
*get_path () const { return m_path
; }
498 void set_path (const diagnostic_path
*path
) { m_path
= path
; }
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
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 bool escape_on_output_p () const { return m_escape_on_output
; }
510 void set_escape_on_output (bool flag
) { m_escape_on_output
= flag
; }
512 const line_maps
*get_line_table () const { return m_line_table
; }
515 bool reject_impossible_fixit (location_t where
);
516 void stop_supporting_fixits ();
517 void maybe_add_fixit (location_t start
,
519 const char *new_content
);
522 static const int STATICALLY_ALLOCATED_RANGES
= 3;
525 line_maps
* const m_line_table
;
526 semi_embedded_vec
<location_range
, STATICALLY_ALLOCATED_RANGES
> m_ranges
;
528 int m_column_override
;
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
;
535 mutable expanded_location m_expanded_location
;
537 static const int MAX_STATIC_FIXIT_HINTS
= 2;
538 semi_embedded_vec
<fixit_hint
*, MAX_STATIC_FIXIT_HINTS
> m_fixit_hints
;
540 const diagnostic_path
*m_path
;
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
551 : m_buffer (NULL
), m_owned (false)
561 label_text (label_text
&&other
)
562 : m_buffer (other
.m_buffer
), m_owned (other
.m_owned
)
567 /* Move assignment. */
568 label_text
& operator= (label_text
&&other
)
572 m_buffer
= other
.m_buffer
;
573 m_owned
= other
.m_owned
;
578 /* Delete the copy ctor and copy-assignment operator. */
579 label_text (const label_text
&) = delete;
580 label_text
& operator= (const label_text
&) = delete;
582 /* Create a label_text instance that borrows BUFFER from a
583 longer-lived owner. */
584 static label_text
borrow (const char *buffer
)
586 return label_text (const_cast <char *> (buffer
), false);
589 /* Create a label_text instance that takes ownership of BUFFER. */
590 static label_text
take (char *buffer
)
592 return label_text (buffer
, true);
601 const char *get () const
606 bool is_owner () const
615 label_text (char *buffer
, bool owned
)
616 : m_buffer (buffer
), m_owned (owned
)
620 /* Abstract base class for labelling a range within a rich_location
621 (e.g. for labelling expressions with their type).
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
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. */
638 virtual ~range_label () {}
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;
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:
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.
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). */
663 fixit_hint (location_t start
,
665 const char *new_content
);
666 ~fixit_hint () { free (m_bytes
); }
668 bool affects_line_p (const line_maps
*set
,
671 location_t
get_start_loc () const { return m_start
; }
672 location_t
get_next_loc () const { return m_next_loc
; }
673 bool maybe_append (location_t start
,
675 const char *new_content
);
677 const char *get_string () const { return m_bytes
; }
678 size_t get_length () const { return m_len
; }
680 bool insertion_p () const { return m_start
== m_next_loc
; }
682 bool ends_with_newline_p () const;
685 /* We don't use source_range here since, unlike most places,
686 this is a half-open/half-closed range:
688 so that we can support insertion via start == next_loc. */
690 location_t m_next_loc
;
695 #endif /* !LIBCPP_RICH_LOCATION_H */