C++: -Wwrite-strings: use location of string constant
[official-gcc.git] / gcc / substring-locations.c
blob82f2f4577f0bb7cc0b1d86fb8e6971ee6d10f9cd
1 /* Source locations within string literals.
2 Copyright (C) 2016-2018 Free Software Foundation, Inc.
4 This file is part of GCC.
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.
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.
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/>. */
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 #include "gcc-rich-location.h"
31 /* Emit a warning governed by option OPT, using SINGULAR_GMSGID as the
32 format string (or if PLURAL_GMSGID is different from SINGULAR_GMSGID,
33 using SINGULAR_GMSGID, PLURAL_GMSGID and N as arguments to ngettext)
34 and AP as its arguments.
36 Attempt to obtain precise location information within a string
37 literal from FMT_LOC.
39 Case 1: if substring location is available, and is within the range of
40 the format string itself, the primary location of the
41 diagnostic is the substring range obtained from FMT_LOC, with the
42 caret at the *end* of the substring range.
44 For example:
46 test.c:90:10: warning: problem with '%i' here [-Wformat=]
47 printf ("hello %i", msg);
50 Case 2: if the substring location is available, but is not within
51 the range of the format string, the primary location is that of the
52 format string, and an note is emitted showing the substring location.
54 For example:
55 test.c:90:10: warning: problem with '%i' here [-Wformat=]
56 printf("hello " INT_FMT " world", msg);
57 ^~~~~~~~~~~~~~~~~~~~~~~~~
58 test.c:19: note: format string is defined here
59 #define INT_FMT "%i"
62 Case 3: if precise substring information is unavailable, the primary
63 location is that of the whole string passed to FMT_LOC's constructor.
64 For example:
66 test.c:90:10: warning: problem with '%i' here [-Wformat=]
67 printf(fmt, msg);
68 ^~~
70 For each of cases 1-3, if param_loc is not UNKNOWN_LOCATION, then it is used
71 as a secondary range within the warning. For example, here it
72 is used with case 1:
74 test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
75 printf ("foo %s bar", long_i + long_j);
76 ~^ ~~~~~~~~~~~~~~~
78 and here with case 2:
80 test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
81 printf ("foo " STR_FMT " bar", long_i + long_j);
82 ^~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
83 test.c:89:16: note: format string is defined here
84 #define STR_FMT "%s"
87 and with case 3:
89 test.c:90:10: warning: '%i' here, but arg 2 is "const char *' [-Wformat=]
90 printf(fmt, msg);
91 ^~~ ~~~
93 If non-NULL, then FMT_LABEL will be used to label the location within the
94 string for cases 1 and 2; if non-NULL, then PARAM_LABEL will be used to label
95 the parameter. For example with case 1:
97 test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
98 printf ("foo %s bar", long_i + long_j);
99 ~^ ~~~~~~~~~~~~~~~
103 and with case 2:
105 test.c:90:10: warning: problem with '%i' here [-Wformat=]
106 printf("hello " INT_FMT " world", msg);
107 ^~~~~~~~~~~~~~~~~~~~~~~~~
108 test.c:19: note: format string is defined here
109 #define INT_FMT "%i"
114 If CORRECTED_SUBSTRING is non-NULL, use it for cases 1 and 2 to provide
115 a fix-it hint, suggesting that it should replace the text within the
116 substring range. For example:
118 test.c:90:10: warning: problem with '%i' here [-Wformat=]
119 printf ("hello %i", msg);
123 Return true if a warning was emitted, false otherwise. */
125 bool
126 format_warning_n_va (const substring_loc &fmt_loc,
127 const range_label *fmt_label,
128 location_t param_loc,
129 const range_label *param_label,
130 const char *corrected_substring,
131 int opt, unsigned HOST_WIDE_INT n,
132 const char *singular_gmsgid,
133 const char *plural_gmsgid, va_list *ap)
135 bool substring_within_range = false;
136 location_t primary_loc;
137 location_t fmt_substring_loc = UNKNOWN_LOCATION;
138 source_range fmt_loc_range
139 = get_range_from_loc (line_table, fmt_loc.get_fmt_string_loc ());
140 const char *err = fmt_loc.get_location (&fmt_substring_loc);
141 source_range fmt_substring_range
142 = get_range_from_loc (line_table, fmt_substring_loc);
143 if (err)
144 /* Case 3: unable to get substring location. */
145 primary_loc = fmt_loc.get_fmt_string_loc ();
146 else
148 if (fmt_substring_range.m_start >= fmt_loc_range.m_start
149 && fmt_substring_range.m_start <= fmt_loc_range.m_finish
150 && fmt_substring_range.m_finish >= fmt_loc_range.m_start
151 && fmt_substring_range.m_finish <= fmt_loc_range.m_finish)
152 /* Case 1. */
154 substring_within_range = true;
155 primary_loc = fmt_substring_loc;
157 else
158 /* Case 2. */
160 substring_within_range = false;
161 primary_loc = fmt_loc.get_fmt_string_loc ();
165 /* Only use fmt_label in the initial warning for case 1. */
166 const range_label *primary_label = NULL;
167 if (substring_within_range)
168 primary_label = fmt_label;
170 gcc_rich_location richloc (primary_loc, primary_label);
172 if (param_loc != UNKNOWN_LOCATION)
173 richloc.add_range (param_loc, false, param_label);
175 if (!err && corrected_substring && substring_within_range)
176 richloc.add_fixit_replace (fmt_substring_range, corrected_substring);
178 diagnostic_info diagnostic;
179 if (singular_gmsgid != plural_gmsgid)
181 unsigned long gtn;
183 if (sizeof n <= sizeof gtn)
184 gtn = n;
185 else
186 /* Use the largest number ngettext can handle, otherwise
187 preserve the six least significant decimal digits for
188 languages where the plural form depends on them. */
189 gtn = n <= ULONG_MAX ? n : n % 1000000LU + 1000000LU;
191 const char *text = ngettext (singular_gmsgid, plural_gmsgid, gtn);
192 diagnostic_set_info_translated (&diagnostic, text, ap, &richloc,
193 DK_WARNING);
195 else
196 diagnostic_set_info (&diagnostic, singular_gmsgid, ap, &richloc,
197 DK_WARNING);
198 diagnostic.option_index = opt;
199 bool warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
201 if (!err && fmt_substring_loc && !substring_within_range)
202 /* Case 2. */
203 if (warned)
205 /* Use fmt_label in the note for case 2. */
206 rich_location substring_richloc (line_table, fmt_substring_loc,
207 fmt_label);
208 if (corrected_substring)
209 substring_richloc.add_fixit_replace (fmt_substring_range,
210 corrected_substring);
211 inform (&substring_richloc,
212 "format string is defined here");
215 return warned;
218 /* Singular-only version of the above. */
220 bool
221 format_warning_va (const substring_loc &fmt_loc,
222 const range_label *fmt_label,
223 location_t param_loc,
224 const range_label *param_label,
225 const char *corrected_substring,
226 int opt, const char *gmsgid, va_list *ap)
228 return format_warning_n_va (fmt_loc, fmt_label, param_loc, param_label,
229 corrected_substring, opt,
230 0, gmsgid, gmsgid, ap);
233 /* Variadic call to format_warning_va. */
235 bool
236 format_warning_at_substring (const substring_loc &fmt_loc,
237 const range_label *fmt_label,
238 location_t param_loc,
239 const range_label *param_label,
240 const char *corrected_substring,
241 int opt, const char *gmsgid, ...)
243 va_list ap;
244 va_start (ap, gmsgid);
245 bool warned = format_warning_va (fmt_loc, fmt_label, param_loc, param_label,
246 corrected_substring, opt, gmsgid, &ap);
247 va_end (ap);
249 return warned;
252 /* Variadic call to format_warning_n_va. */
254 bool
255 format_warning_at_substring_n (const substring_loc &fmt_loc,
256 const range_label *fmt_label,
257 location_t param_loc,
258 const range_label *param_label,
259 const char *corrected_substring,
260 int opt, unsigned HOST_WIDE_INT n,
261 const char *singular_gmsgid,
262 const char *plural_gmsgid, ...)
264 va_list ap;
265 va_start (ap, plural_gmsgid);
266 bool warned = format_warning_n_va (fmt_loc, fmt_label, param_loc, param_label,
267 corrected_substring,
268 opt, n, singular_gmsgid, plural_gmsgid,
269 &ap);
270 va_end (ap);
272 return warned;
275 /* Attempt to determine the source location of the substring.
276 If successful, return NULL and write the source location to *OUT_LOC.
277 Otherwise return an error message. Error messages are intended
278 for GCC developers (to help debugging) rather than for end-users. */
280 const char *
281 substring_loc::get_location (location_t *out_loc) const
283 gcc_assert (out_loc);
284 return lang_hooks.get_substring_location (*this, out_loc);