111
|
1 /* Source locations within string literals.
|
|
2 Copyright (C) 2016-2017 Free Software Foundation, Inc.
|
|
3
|
|
4 This file is part of GCC.
|
|
5
|
|
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.
|
|
10
|
|
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.
|
|
15
|
|
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/>. */
|
|
19
|
|
20 #include "config.h"
|
|
21 #include "system.h"
|
|
22 #include "coretypes.h"
|
|
23 #include "diagnostic.h"
|
|
24 #include "cpplib.h"
|
|
25 #include "tree.h"
|
|
26 #include "langhooks.h"
|
|
27 #include "substring-locations.h"
|
|
28
|
|
29 /* Emit a warning governed by option OPT, using GMSGID as the format
|
|
30 string and AP as its arguments.
|
|
31
|
|
32 Attempt to obtain precise location information within a string
|
|
33 literal from FMT_LOC.
|
|
34
|
|
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.
|
|
39
|
|
40 For example:
|
|
41
|
|
42 test.c:90:10: warning: problem with '%i' here [-Wformat=]
|
|
43 printf ("hello %i", msg);
|
|
44 ~^
|
|
45
|
|
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.
|
|
49
|
|
50 For example:
|
|
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
|
|
55 #define INT_FMT "%i"
|
|
56 ~^
|
|
57
|
|
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.
|
|
60 For example:
|
|
61
|
|
62 test.c:90:10: warning: problem with '%i' here [-Wformat=]
|
|
63 printf(fmt, msg);
|
|
64 ^~~
|
|
65
|
|
66 For each of cases 1-3, if param_loc is not UNKNOWN_LOCATION, then it is used
|
|
67 as a secondary range within the warning. For example, here it
|
|
68 is used with case 1:
|
|
69
|
|
70 test.c:90:16: warning: '%s' here but arg 2 has 'long' type [-Wformat=]
|
|
71 printf ("foo %s bar", long_i + long_j);
|
|
72 ~^ ~~~~~~~~~~~~~~~
|
|
73
|
|
74 and here with case 2:
|
|
75
|
|
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
|
|
80 #define STR_FMT "%s"
|
|
81 ~^
|
|
82
|
|
83 and with case 3:
|
|
84
|
|
85 test.c:90:10: warning: '%i' here, but arg 2 is "const char *' [-Wformat=]
|
|
86 printf(fmt, msg);
|
|
87 ^~~ ~~~
|
|
88
|
|
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:
|
|
92
|
|
93 test.c:90:10: warning: problem with '%i' here [-Wformat=]
|
|
94 printf ("hello %i", msg);
|
|
95 ~^
|
|
96 %s
|
|
97
|
|
98 Return true if a warning was emitted, false otherwise. */
|
|
99
|
|
100 ATTRIBUTE_GCC_DIAG (5,0)
|
|
101 bool
|
|
102 format_warning_va (const substring_loc &fmt_loc,
|
|
103 location_t param_loc,
|
|
104 const char *corrected_substring,
|
|
105 int opt, const char *gmsgid, va_list *ap)
|
|
106 {
|
|
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);
|
|
115 if (err)
|
|
116 /* Case 3: unable to get substring location. */
|
|
117 primary_loc = fmt_loc.get_fmt_string_loc ();
|
|
118 else
|
|
119 {
|
|
120 if (fmt_substring_range.m_start >= fmt_loc_range.m_start
|
|
121 && fmt_substring_range.m_start <= fmt_loc_range.m_finish
|
|
122 && fmt_substring_range.m_finish >= fmt_loc_range.m_start
|
|
123 && fmt_substring_range.m_finish <= fmt_loc_range.m_finish)
|
|
124 /* Case 1. */
|
|
125 {
|
|
126 substring_within_range = true;
|
|
127 primary_loc = fmt_substring_loc;
|
|
128 }
|
|
129 else
|
|
130 /* Case 2. */
|
|
131 {
|
|
132 substring_within_range = false;
|
|
133 primary_loc = fmt_loc.get_fmt_string_loc ();
|
|
134 }
|
|
135 }
|
|
136
|
|
137 rich_location richloc (line_table, primary_loc);
|
|
138
|
|
139 if (param_loc != UNKNOWN_LOCATION)
|
|
140 richloc.add_range (param_loc, false);
|
|
141
|
|
142 if (!err && corrected_substring && substring_within_range)
|
|
143 richloc.add_fixit_replace (fmt_substring_range, corrected_substring);
|
|
144
|
|
145 diagnostic_info diagnostic;
|
|
146 diagnostic_set_info (&diagnostic, gmsgid, ap, &richloc, DK_WARNING);
|
|
147 diagnostic.option_index = opt;
|
|
148 bool warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
|
|
149
|
|
150 if (!err && fmt_substring_loc && !substring_within_range)
|
|
151 /* Case 2. */
|
|
152 if (warned)
|
|
153 {
|
|
154 rich_location substring_richloc (line_table, fmt_substring_loc);
|
|
155 if (corrected_substring)
|
|
156 substring_richloc.add_fixit_replace (fmt_substring_range,
|
|
157 corrected_substring);
|
|
158 inform_at_rich_loc (&substring_richloc,
|
|
159 "format string is defined here");
|
|
160 }
|
|
161
|
|
162 return warned;
|
|
163 }
|
|
164
|
|
165 /* Variadic call to format_warning_va. */
|
|
166
|
|
167 bool
|
|
168 format_warning_at_substring (const substring_loc &fmt_loc,
|
|
169 location_t param_loc,
|
|
170 const char *corrected_substring,
|
|
171 int opt, const char *gmsgid, ...)
|
|
172 {
|
|
173 va_list ap;
|
|
174 va_start (ap, gmsgid);
|
|
175 bool warned = format_warning_va (fmt_loc, param_loc, corrected_substring,
|
|
176 opt, gmsgid, &ap);
|
|
177 va_end (ap);
|
|
178
|
|
179 return warned;
|
|
180 }
|
|
181
|
|
182 /* Attempt to determine the source location of the substring.
|
|
183 If successful, return NULL and write the source location to *OUT_LOC.
|
|
184 Otherwise return an error message. Error messages are intended
|
|
185 for GCC developers (to help debugging) rather than for end-users. */
|
|
186
|
|
187 const char *
|
|
188 substring_loc::get_location (location_t *out_loc) const
|
|
189 {
|
|
190 gcc_assert (out_loc);
|
|
191 return lang_hooks.get_substring_location (*this, out_loc);
|
|
192 }
|