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