| 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 |  |