1 /* Source locations within string literals. 2 Copyright (C) 2016-2017 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 "diagnostic.h" 24 #include "cpplib.h" 25 #include "tree.h" 26 #include "langhooks.h" 27 #include "substring-locations.h" 28 29 /* Emit a warning governed by option OPT, using GMSGID as the format 30 string and AP as its arguments. 31 32 Attempt to obtain precise location information within a string 33 literal from FMT_LOC. 34 35 Case 1: if substring location is available, and is within the range of 36 the format string itself, the primary location of the 37 diagnostic is the substring range obtained from FMT_LOC, with the 38 caret at the *end* of the substring range. 39 40 For example: 41 42 test.c:90:10: warning: problem with '%i' here [-Wformat=] 43 printf ("hello %i", msg); 44 ~^ 45 46 Case 2: if the substring location is available, but is not within 47 the range of the format string, the primary location is that of the 48 format string, and an note is emitted showing the substring location. 49 50 For example: 51 test.c:90:10: warning: problem with '%i' here [-Wformat=] 52 printf("hello " INT_FMT " world", msg); 53 ^~~~~~~~~~~~~~~~~~~~~~~~~ 54 test.c:19: note: format string is defined here 55 #define INT_FMT "%i" 56 ~^ 57 58 Case 3: if precise substring information is unavailable, the primary 59 location is that of the whole string passed to FMT_LOC's constructor. 60 For example: 61 62 test.c:90:10: warning: problem with '%i' here [-Wformat=] 63 printf(fmt, msg); 64 ^~~ 65 66 For each of cases 1-3, if param_range is non-NULL, then it is used 67 as a secondary range within the warning. For example, here it 68 is used with case 1: 69 70 test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=] 71 printf ("foo %s bar", long_i + long_j); 72 ~^ ~~~~~~~~~~~~~~~ 73 74 and here with case 2: 75 76 test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=] 77 printf ("foo " STR_FMT " bar", long_i + long_j); 78 ^~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~ 79 test.c:89:16: note: format string is defined here 80 #define STR_FMT "%s" 81 ~^ 82 83 and with case 3: 84 85 test.c:90:10: warning: '%i' here, but arg 2 is "const char *' [-Wformat=] 86 printf(fmt, msg); 87 ^~~ ~~~ 88 89 If CORRECTED_SUBSTRING is non-NULL, use it for cases 1 and 2 to provide 90 a fix-it hint, suggesting that it should replace the text within the 91 substring range. For example: 92 93 test.c:90:10: warning: problem with '%i' here [-Wformat=] 94 printf ("hello %i", msg); 95 ~^ 96 %s 97 98 Return true if a warning was emitted, false otherwise. */ 99 100 ATTRIBUTE_GCC_DIAG (5,0) 101 bool 102 format_warning_va (const substring_loc &fmt_loc, 103 const source_range *param_range, 104 const char *corrected_substring, 105 int opt, const char *gmsgid, va_list *ap) 106 { 107 bool substring_within_range = false; 108 location_t primary_loc; 109 location_t fmt_substring_loc = UNKNOWN_LOCATION; 110 source_range fmt_loc_range 111 = get_range_from_loc (line_table, fmt_loc.get_fmt_string_loc ()); 112 const char *err = fmt_loc.get_location (&fmt_substring_loc); 113 source_range fmt_substring_range 114 = get_range_from_loc (line_table, fmt_substring_loc); 115 if (err) 116 /* Case 3: unable to get substring location. */ 117 primary_loc = fmt_loc.get_fmt_string_loc (); 118 else 119 { 120 if (fmt_substring_range.m_start >= fmt_loc_range.m_start 121 && fmt_substring_range.m_start <= fmt_loc_range.m_finish 122 && fmt_substring_range.m_finish >= fmt_loc_range.m_start 123 && fmt_substring_range.m_finish <= fmt_loc_range.m_finish) 124 /* Case 1. */ 125 { 126 substring_within_range = true; 127 primary_loc = fmt_substring_loc; 128 } 129 else 130 /* Case 2. */ 131 { 132 substring_within_range = false; 133 primary_loc = fmt_loc.get_fmt_string_loc (); 134 } 135 } 136 137 rich_location richloc (line_table, primary_loc); 138 139 if (param_range) 140 { 141 location_t param_loc = make_location (param_range->m_start, 142 param_range->m_start, 143 param_range->m_finish); 144 richloc.add_range (param_loc, false); 145 } 146 147 if (!err && corrected_substring && substring_within_range) 148 richloc.add_fixit_replace (fmt_substring_range, corrected_substring); 149 150 diagnostic_info diagnostic; 151 diagnostic_set_info (&diagnostic, gmsgid, ap, &richloc, DK_WARNING); 152 diagnostic.option_index = opt; 153 bool warned = report_diagnostic (&diagnostic); 154 155 if (!err && fmt_substring_loc && !substring_within_range) 156 /* Case 2. */ 157 if (warned) 158 { 159 rich_location substring_richloc (line_table, fmt_substring_loc); 160 if (corrected_substring) 161 substring_richloc.add_fixit_replace (fmt_substring_range, 162 corrected_substring); 163 inform_at_rich_loc (&substring_richloc, 164 "format string is defined here"); 165 } 166 167 return warned; 168 } 169 170 /* Variadic call to format_warning_va. */ 171 172 bool 173 format_warning_at_substring (const substring_loc &fmt_loc, 174 const source_range *param_range, 175 const char *corrected_substring, 176 int opt, const char *gmsgid, ...) 177 { 178 va_list ap; 179 va_start (ap, gmsgid); 180 bool warned = format_warning_va (fmt_loc, param_range, corrected_substring, 181 opt, gmsgid, &ap); 182 va_end (ap); 183 184 return warned; 185 } 186 187 /* Attempt to determine the source location of the substring. 188 If successful, return NULL and write the source location to *OUT_LOC. 189 Otherwise return an error message. Error messages are intended 190 for GCC developers (to help debugging) rather than for end-users. */ 191 192 const char * 193 substring_loc::get_location (location_t *out_loc) const 194 { 195 gcc_assert (out_loc); 196 return lang_hooks.get_substring_location (*this, out_loc); 197 } 198