1 /* Source locations within string literals. 2 Copyright (C) 2016-2018 Free Software Foundation, Inc. 3 4 This file is part of GCC. 5 6 GCC is free software; you can redistribute it and/or modify it under 7 the terms of the GNU General Public License as published by the Free 8 Software Foundation; either version 3, or (at your option) any later 9 version. 10 11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12 WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GCC; see the file COPYING3. If not see 18 <http://www.gnu.org/licenses/>. */ 19 20 #include "config.h" 21 #include "system.h" 22 #include "coretypes.h" 23 #include "intl.h" 24 #include "diagnostic.h" 25 #include "cpplib.h" 26 #include "tree.h" 27 #include "langhooks.h" 28 #include "substring-locations.h" 29 30 /* Emit a warning governed by option OPT, using SINGULAR_GMSGID as the 31 format string (or if PLURAL_GMSGID is different from SINGULAR_GMSGID, 32 using SINGULAR_GMSGID, PLURAL_GMSGID and N as arguments to ngettext) 33 and AP as its arguments. 34 35 Attempt to obtain precise location information within a string 36 literal from FMT_LOC. 37 38 Case 1: if substring location is available, and is within the range of 39 the format string itself, the primary location of the 40 diagnostic is the substring range obtained from FMT_LOC, with the 41 caret at the *end* of the substring range. 42 43 For example: 44 45 test.c:90:10: warning: problem with '%i' here [-Wformat=] 46 printf ("hello %i", msg); 47 ~^ 48 49 Case 2: if the substring location is available, but is not within 50 the range of the format string, the primary location is that of the 51 format string, and an note is emitted showing the substring location. 52 53 For example: 54 test.c:90:10: warning: problem with '%i' here [-Wformat=] 55 printf("hello " INT_FMT " world", msg); 56 ^~~~~~~~~~~~~~~~~~~~~~~~~ 57 test.c:19: note: format string is defined here 58 #define INT_FMT "%i" 59 ~^ 60 61 Case 3: if precise substring information is unavailable, the primary 62 location is that of the whole string passed to FMT_LOC's constructor. 63 For example: 64 65 test.c:90:10: warning: problem with '%i' here [-Wformat=] 66 printf(fmt, msg); 67 ^~~ 68 69 For each of cases 1-3, if param_loc is not UNKNOWN_LOCATION, then it is used 70 as a secondary range within the warning. For example, here it 71 is used with case 1: 72 73 test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=] 74 printf ("foo %s bar", long_i + long_j); 75 ~^ ~~~~~~~~~~~~~~~ 76 77 and here with case 2: 78 79 test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=] 80 printf ("foo " STR_FMT " bar", long_i + long_j); 81 ^~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~ 82 test.c:89:16: note: format string is defined here 83 #define STR_FMT "%s" 84 ~^ 85 86 and with case 3: 87 88 test.c:90:10: warning: '%i' here, but arg 2 is "const char *' [-Wformat=] 89 printf(fmt, msg); 90 ^~~ ~~~ 91 92 If CORRECTED_SUBSTRING is non-NULL, use it for cases 1 and 2 to provide 93 a fix-it hint, suggesting that it should replace the text within the 94 substring range. For example: 95 96 test.c:90:10: warning: problem with '%i' here [-Wformat=] 97 printf ("hello %i", msg); 98 ~^ 99 %s 100 101 Return true if a warning was emitted, false otherwise. */ 102 103 bool 104 format_warning_n_va (const substring_loc &fmt_loc, 105 location_t param_loc, 106 const char *corrected_substring, 107 int opt, unsigned HOST_WIDE_INT n, 108 const char *singular_gmsgid, 109 const char *plural_gmsgid, va_list *ap) 110 { 111 bool substring_within_range = false; 112 location_t primary_loc; 113 location_t fmt_substring_loc = UNKNOWN_LOCATION; 114 source_range fmt_loc_range 115 = get_range_from_loc (line_table, fmt_loc.get_fmt_string_loc ()); 116 const char *err = fmt_loc.get_location (&fmt_substring_loc); 117 source_range fmt_substring_range 118 = get_range_from_loc (line_table, fmt_substring_loc); 119 if (err) 120 /* Case 3: unable to get substring location. */ 121 primary_loc = fmt_loc.get_fmt_string_loc (); 122 else 123 { 124 if (fmt_substring_range.m_start >= fmt_loc_range.m_start 125 && fmt_substring_range.m_start <= fmt_loc_range.m_finish 126 && fmt_substring_range.m_finish >= fmt_loc_range.m_start 127 && fmt_substring_range.m_finish <= fmt_loc_range.m_finish) 128 /* Case 1. */ 129 { 130 substring_within_range = true; 131 primary_loc = fmt_substring_loc; 132 } 133 else 134 /* Case 2. */ 135 { 136 substring_within_range = false; 137 primary_loc = fmt_loc.get_fmt_string_loc (); 138 } 139 } 140 141 rich_location richloc (line_table, primary_loc); 142 143 if (param_loc != UNKNOWN_LOCATION) 144 richloc.add_range (param_loc, false); 145 146 if (!err && corrected_substring && substring_within_range) 147 richloc.add_fixit_replace (fmt_substring_range, corrected_substring); 148 149 diagnostic_info diagnostic; 150 if (singular_gmsgid != plural_gmsgid) 151 { 152 unsigned long gtn; 153 154 if (sizeof n <= sizeof gtn) 155 gtn = n; 156 else 157 /* Use the largest number ngettext can handle, otherwise 158 preserve the six least significant decimal digits for 159 languages where the plural form depends on them. */ 160 gtn = n <= ULONG_MAX ? n : n % 1000000LU + 1000000LU; 161 162 const char *text = ngettext (singular_gmsgid, plural_gmsgid, gtn); 163 diagnostic_set_info_translated (&diagnostic, text, ap, &richloc, 164 DK_WARNING); 165 } 166 else 167 diagnostic_set_info (&diagnostic, singular_gmsgid, ap, &richloc, 168 DK_WARNING); 169 diagnostic.option_index = opt; 170 bool warned = diagnostic_report_diagnostic (global_dc, &diagnostic); 171 172 if (!err && fmt_substring_loc && !substring_within_range) 173 /* Case 2. */ 174 if (warned) 175 { 176 rich_location substring_richloc (line_table, fmt_substring_loc); 177 if (corrected_substring) 178 substring_richloc.add_fixit_replace (fmt_substring_range, 179 corrected_substring); 180 inform (&substring_richloc, 181 "format string is defined here"); 182 } 183 184 return warned; 185 } 186 187 /* Singular-only version of the above. */ 188 189 bool 190 format_warning_va (const substring_loc &fmt_loc, 191 location_t param_loc, 192 const char *corrected_substring, 193 int opt, const char *gmsgid, va_list *ap) 194 { 195 return format_warning_n_va (fmt_loc, param_loc, corrected_substring, opt, 196 0, gmsgid, gmsgid, ap); 197 } 198 199 /* Variadic call to format_warning_va. */ 200 201 bool 202 format_warning_at_substring (const substring_loc &fmt_loc, 203 location_t param_loc, 204 const char *corrected_substring, 205 int opt, const char *gmsgid, ...) 206 { 207 va_list ap; 208 va_start (ap, gmsgid); 209 bool warned = format_warning_va (fmt_loc, param_loc, corrected_substring, 210 opt, gmsgid, &ap); 211 va_end (ap); 212 213 return warned; 214 } 215 216 /* Variadic call to format_warning_n_va. */ 217 218 bool 219 format_warning_at_substring_n (const substring_loc &fmt_loc, 220 location_t param_loc, 221 const char *corrected_substring, 222 int opt, unsigned HOST_WIDE_INT n, 223 const char *singular_gmsgid, 224 const char *plural_gmsgid, ...) 225 { 226 va_list ap; 227 va_start (ap, plural_gmsgid); 228 bool warned = format_warning_n_va (fmt_loc, param_loc, corrected_substring, 229 opt, n, singular_gmsgid, plural_gmsgid, 230 &ap); 231 va_end (ap); 232 233 return warned; 234 } 235 236 /* Attempt to determine the source location of the substring. 237 If successful, return NULL and write the source location to *OUT_LOC. 238 Otherwise return an error message. Error messages are intended 239 for GCC developers (to help debugging) rather than for end-users. */ 240 241 const char * 242 substring_loc::get_location (location_t *out_loc) const 243 { 244 gcc_assert (out_loc); 245 return lang_hooks.get_substring_location (*this, out_loc); 246 } 247