2018-05-15 Richard Biener <rguenther@suse.de>
[official-gcc.git] / gcc / substring-locations.c
blob2d7f0c15133738feeb22827636ce86b2ba3b13f5
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"
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
36 literal from FMT_LOC.
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.
43 For example:
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.
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"
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:
65 test.c:90:10: warning: problem with '%i' here [-Wformat=]
66 printf(fmt, msg);
67 ^~~
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:
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 ~^ ~~~~~~~~~~~~~~~
77 and here with case 2:
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"
86 and with case 3:
88 test.c:90:10: warning: '%i' here, but arg 2 is "const char *' [-Wformat=]
89 printf(fmt, msg);
90 ^~~ ~~~
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. */
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)
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
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. */
130 substring_within_range = true;
131 primary_loc = fmt_substring_loc;
133 else
134 /* Case 2. */
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)
152 unsigned long gtn;
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;
162 const char *text = ngettext (singular_gmsgid, plural_gmsgid, gtn);
163 diagnostic_set_info_translated (&diagnostic, text, ap, &richloc,
164 DK_WARNING);
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);
172 if (!err && fmt_substring_loc && !substring_within_range)
173 /* Case 2. */
174 if (warned)
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");
184 return warned;
187 /* Singular-only version of the above. */
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)
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. */
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, ...)
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);
213 return warned;
216 /* Variadic call to format_warning_n_va. */
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, ...)
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);
233 return warned;
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. */
241 const char *
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);