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
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
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/>. */
22 #include "coretypes.h"
24 #include "diagnostic.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
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.
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.
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
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.
66 test.c:90:10: warning: problem with '%i' here [-Wformat=]
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
74 test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
75 printf ("foo %s bar", long_i + long_j);
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
89 test.c:90:10: warning: '%i' here, but arg 2 is "const char *' [-Wformat=]
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);
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
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. */
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
);
144 /* Case 3: unable to get substring location. */
145 primary_loc
= fmt_loc
.get_fmt_string_loc ();
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
)
154 substring_within_range
= true;
155 primary_loc
= fmt_substring_loc
;
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 auto_diagnostic_group d
;
171 gcc_rich_location
richloc (primary_loc
, primary_label
);
173 if (param_loc
!= UNKNOWN_LOCATION
)
174 richloc
.add_range (param_loc
, SHOW_RANGE_WITHOUT_CARET
, param_label
);
176 if (!err
&& corrected_substring
&& substring_within_range
)
177 richloc
.add_fixit_replace (fmt_substring_range
, corrected_substring
);
179 diagnostic_info diagnostic
;
180 if (singular_gmsgid
!= plural_gmsgid
)
184 if (sizeof n
<= sizeof gtn
)
187 /* Use the largest number ngettext can handle, otherwise
188 preserve the six least significant decimal digits for
189 languages where the plural form depends on them. */
190 gtn
= n
<= ULONG_MAX
? n
: n
% 1000000LU + 1000000LU;
192 const char *text
= ngettext (singular_gmsgid
, plural_gmsgid
, gtn
);
193 diagnostic_set_info_translated (&diagnostic
, text
, ap
, &richloc
,
197 diagnostic_set_info (&diagnostic
, singular_gmsgid
, ap
, &richloc
,
199 diagnostic
.option_index
= opt
;
200 bool warned
= diagnostic_report_diagnostic (global_dc
, &diagnostic
);
202 if (!err
&& fmt_substring_loc
&& !substring_within_range
)
206 /* Use fmt_label in the note for case 2. */
207 rich_location
substring_richloc (line_table
, fmt_substring_loc
,
209 if (corrected_substring
)
210 substring_richloc
.add_fixit_replace (fmt_substring_range
,
211 corrected_substring
);
212 inform (&substring_richloc
,
213 "format string is defined here");
219 /* Singular-only version of the above. */
222 format_warning_va (const substring_loc
&fmt_loc
,
223 const range_label
*fmt_label
,
224 location_t param_loc
,
225 const range_label
*param_label
,
226 const char *corrected_substring
,
227 int opt
, const char *gmsgid
, va_list *ap
)
229 return format_warning_n_va (fmt_loc
, fmt_label
, param_loc
, param_label
,
230 corrected_substring
, opt
,
231 0, gmsgid
, gmsgid
, ap
);
234 /* Variadic call to format_warning_va. */
237 format_warning_at_substring (const substring_loc
&fmt_loc
,
238 const range_label
*fmt_label
,
239 location_t param_loc
,
240 const range_label
*param_label
,
241 const char *corrected_substring
,
242 int opt
, const char *gmsgid
, ...)
245 va_start (ap
, gmsgid
);
246 bool warned
= format_warning_va (fmt_loc
, fmt_label
, param_loc
, param_label
,
247 corrected_substring
, opt
, gmsgid
, &ap
);
253 /* Variadic call to format_warning_n_va. */
256 format_warning_at_substring_n (const substring_loc
&fmt_loc
,
257 const range_label
*fmt_label
,
258 location_t param_loc
,
259 const range_label
*param_label
,
260 const char *corrected_substring
,
261 int opt
, unsigned HOST_WIDE_INT n
,
262 const char *singular_gmsgid
,
263 const char *plural_gmsgid
, ...)
266 va_start (ap
, plural_gmsgid
);
267 bool warned
= format_warning_n_va (fmt_loc
, fmt_label
, param_loc
, param_label
,
269 opt
, n
, singular_gmsgid
, plural_gmsgid
,
276 /* Attempt to determine the source location of the substring.
277 If successful, return NULL and write the source location to *OUT_LOC.
278 Otherwise return an error message. Error messages are intended
279 for GCC developers (to help debugging) rather than for end-users. */
282 substring_loc::get_location (location_t
*out_loc
) const
284 gcc_assert (out_loc
);
285 return lang_hooks
.get_substring_location (*this, out_loc
);