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