1 /* Source locations within string literals.
2 Copyright (C) 2016 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"
23 #include "diagnostic.h"
26 #include "langhooks.h"
27 #include "substring-locations.h"
29 /* Emit a warning governed by option OPT, using GMSGID as the format
30 string and AP as its arguments.
32 Attempt to obtain precise location information within a string
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.
42 test.c:90:10: warning: problem with '%i' here [-Wformat=]
43 printf ("hello %i", msg);
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.
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
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.
62 test.c:90:10: warning: problem with '%i' here [-Wformat=]
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
70 test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
71 printf ("foo %s bar", long_i + long_j);
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
85 test.c:90:10: warning: '%i' here, but arg 2 is "const char *' [-Wformat=]
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:
93 test.c:90:10: warning: problem with '%i' here [-Wformat=]
94 printf ("hello %i", msg);
98 Return true if a warning was emitted, false otherwise. */
100 ATTRIBUTE_GCC_DIAG (5,0)
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
)
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
);
116 /* Case 3: unable to get substring location. */
117 primary_loc
= fmt_loc
.get_fmt_string_loc ();
120 if (fmt_substring_range
.m_start
>= fmt_loc_range
.m_start
121 && fmt_substring_range
.m_finish
<= fmt_loc_range
.m_finish
)
124 substring_within_range
= true;
125 primary_loc
= fmt_substring_loc
;
130 substring_within_range
= false;
131 primary_loc
= fmt_loc
.get_fmt_string_loc ();
135 rich_location
richloc (line_table
, primary_loc
);
139 location_t param_loc
= make_location (param_range
->m_start
,
140 param_range
->m_start
,
141 param_range
->m_finish
);
142 richloc
.add_range (param_loc
, false);
145 if (!err
&& corrected_substring
&& substring_within_range
)
146 richloc
.add_fixit_replace (fmt_substring_range
, corrected_substring
);
148 diagnostic_info diagnostic
;
149 diagnostic_set_info (&diagnostic
, gmsgid
, ap
, &richloc
, DK_WARNING
);
150 diagnostic
.option_index
= opt
;
151 bool warned
= report_diagnostic (&diagnostic
);
153 if (!err
&& fmt_substring_loc
&& !substring_within_range
)
157 rich_location
substring_richloc (line_table
, fmt_substring_loc
);
158 if (corrected_substring
)
159 substring_richloc
.add_fixit_replace (fmt_substring_range
,
160 corrected_substring
);
161 inform_at_rich_loc (&substring_richloc
,
162 "format string is defined here");
168 /* Variadic call to format_warning_va. */
171 format_warning_at_substring (const substring_loc
&fmt_loc
,
172 const source_range
*param_range
,
173 const char *corrected_substring
,
174 int opt
, const char *gmsgid
, ...)
177 va_start (ap
, gmsgid
);
178 bool warned
= format_warning_va (fmt_loc
, param_range
, corrected_substring
,
185 /* Attempt to determine the source location of the substring.
186 If successful, return NULL and write the source location to *OUT_LOC.
187 Otherwise return an error message. Error messages are intended
188 for GCC developers (to help debugging) rather than for end-users. */
191 substring_loc::get_location (location_t
*out_loc
) const
193 gcc_assert (out_loc
);
194 return lang_hooks
.get_substring_location (*this, out_loc
);