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"
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.
35 Attempt to obtain precise location information within a string
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.
45 test.c:90:10: warning: problem with '%i' here [-Wformat=]
46 printf ("hello %i", msg);
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.
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
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.
65 test.c:90:10: warning: problem with '%i' here [-Wformat=]
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
73 test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
74 printf ("foo %s bar", long_i + long_j);
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
88 test.c:90:10: warning: '%i' here, but arg 2 is "const char *' [-Wformat=]
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:
96 test.c:90:10: warning: problem with '%i' here [-Wformat=]
97 printf ("hello %i", msg);
101 Return true if a warning was emitted, false otherwise. */
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
)
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
);
120 /* Case 3: unable to get substring location. */
121 primary_loc
= fmt_loc
.get_fmt_string_loc ();
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
)
130 substring_within_range
= true;
131 primary_loc
= fmt_substring_loc
;
136 substring_within_range
= false;
137 primary_loc
= fmt_loc
.get_fmt_string_loc ();
141 rich_location
richloc (line_table
, primary_loc
);
143 if (param_loc
!= UNKNOWN_LOCATION
)
144 richloc
.add_range (param_loc
, false);
146 if (!err
&& corrected_substring
&& substring_within_range
)
147 richloc
.add_fixit_replace (fmt_substring_range
, corrected_substring
);
149 diagnostic_info diagnostic
;
150 if (singular_gmsgid
!= plural_gmsgid
)
154 if (sizeof n
<= sizeof gtn
)
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;
162 const char *text
= ngettext (singular_gmsgid
, plural_gmsgid
, gtn
);
163 diagnostic_set_info_translated (&diagnostic
, text
, ap
, &richloc
,
167 diagnostic_set_info (&diagnostic
, singular_gmsgid
, ap
, &richloc
,
169 diagnostic
.option_index
= opt
;
170 bool warned
= diagnostic_report_diagnostic (global_dc
, &diagnostic
);
172 if (!err
&& fmt_substring_loc
&& !substring_within_range
)
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");
187 /* Singular-only version of the above. */
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
)
195 return format_warning_n_va (fmt_loc
, param_loc
, corrected_substring
, opt
,
196 0, gmsgid
, gmsgid
, ap
);
199 /* Variadic call to format_warning_va. */
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
, ...)
208 va_start (ap
, gmsgid
);
209 bool warned
= format_warning_va (fmt_loc
, param_loc
, corrected_substring
,
216 /* Variadic call to format_warning_n_va. */
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
, ...)
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
,
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. */
242 substring_loc::get_location (location_t
*out_loc
) const
244 gcc_assert (out_loc
);
245 return lang_hooks
.get_substring_location (*this, out_loc
);