]>
Commit | Line | Data |
---|---|---|
ebedc9a3 | 1 | /* Implementation of gcc_rich_location class |
a945c346 | 2 | Copyright (C) 2014-2024 Free Software Foundation, Inc. |
ebedc9a3 DM |
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 "tm.h" | |
24 | #include "rtl.h" | |
25 | #include "hash-set.h" | |
ebedc9a3 | 26 | #include "vec.h" |
ebedc9a3 DM |
27 | #include "input.h" |
28 | #include "alias.h" | |
29 | #include "symtab.h" | |
ebedc9a3 DM |
30 | #include "inchash.h" |
31 | #include "tree-core.h" | |
32 | #include "tree.h" | |
33 | #include "diagnostic-core.h" | |
34 | #include "gcc-rich-location.h" | |
35 | #include "print-tree.h" | |
36 | #include "pretty-print.h" | |
37 | #include "intl.h" | |
38 | #include "cpplib.h" | |
39 | #include "diagnostic.h" | |
40 | ||
96e6ae57 DM |
41 | /* Add a range to the rich_location, covering expression EXPR, |
42 | using LABEL if non-NULL. */ | |
ebedc9a3 DM |
43 | |
44 | void | |
96e6ae57 | 45 | gcc_rich_location::add_expr (tree expr, range_label *label) |
ebedc9a3 DM |
46 | { |
47 | gcc_assert (expr); | |
48 | ||
40499f81 | 49 | if (CAN_HAVE_RANGE_P (expr)) |
85204e23 | 50 | add_range (EXPR_LOCATION (expr), SHOW_RANGE_WITHOUT_CARET, label); |
ebedc9a3 DM |
51 | } |
52 | ||
96e6ae57 DM |
53 | /* If T is an expression, add a range for it to the rich_location, |
54 | using LABEL if non-NULL. */ | |
ebedc9a3 DM |
55 | |
56 | void | |
96e6ae57 | 57 | gcc_rich_location::maybe_add_expr (tree t, range_label *label) |
ebedc9a3 DM |
58 | { |
59 | if (EXPR_P (t)) | |
96e6ae57 | 60 | add_expr (t, label); |
ebedc9a3 | 61 | } |
264757fb DM |
62 | |
63 | /* Add a fixit hint suggesting replacing the range at MISSPELLED_TOKEN_LOC | |
64 | with the identifier HINT_ID. */ | |
65 | ||
66 | void | |
67 | gcc_rich_location::add_fixit_misspelled_id (location_t misspelled_token_loc, | |
68 | tree hint_id) | |
69 | { | |
70 | gcc_assert (TREE_CODE (hint_id) == IDENTIFIER_NODE); | |
71 | ||
f9087798 | 72 | add_fixit_replace (misspelled_token_loc, IDENTIFIER_POINTER (hint_id)); |
de6a69ee | 73 | } |
1a3a7b4e DM |
74 | |
75 | /* Return true if there is nothing on LOC's line before LOC. */ | |
76 | ||
77 | static bool | |
1bdd665a DM |
78 | blank_line_before_p (file_cache &fc, |
79 | location_t loc) | |
1a3a7b4e DM |
80 | { |
81 | expanded_location exploc = expand_location (loc); | |
1bdd665a | 82 | char_span line = fc.get_source_line (exploc.file, exploc.line); |
1a3a7b4e DM |
83 | if (!line) |
84 | return false; | |
85 | if (line.length () < (size_t)exploc.column) | |
86 | return false; | |
87 | /* Columns are 1-based. */ | |
88 | for (int column = 1; column < exploc.column; ++column) | |
89 | if (!ISSPACE (line[column - 1])) | |
90 | return false; | |
91 | return true; | |
92 | } | |
93 | ||
94 | /* Subroutine of gcc_rich_location::add_fixit_insert_formatted. | |
95 | Return true if we should add the content on its own line, | |
96 | false otherwise. | |
97 | If true is returned then *OUT_START_OF_LINE is written to. */ | |
98 | ||
99 | static bool | |
1bdd665a DM |
100 | use_new_line (file_cache &fc, |
101 | location_t insertion_point, location_t indent, | |
1a3a7b4e DM |
102 | location_t *out_start_of_line) |
103 | { | |
104 | if (indent == UNKNOWN_LOCATION) | |
105 | return false; | |
106 | const line_map *indent_map = linemap_lookup (line_table, indent); | |
107 | if (linemap_macro_expansion_map_p (indent_map)) | |
108 | return false; | |
109 | ||
1bdd665a | 110 | if (!blank_line_before_p (fc, insertion_point)) |
1a3a7b4e DM |
111 | return false; |
112 | ||
113 | /* Locate the start of the line containing INSERTION_POINT. */ | |
114 | const line_map *insertion_point_map | |
115 | = linemap_lookup (line_table, insertion_point); | |
116 | if (linemap_macro_expansion_map_p (insertion_point_map)) | |
117 | return false; | |
118 | const line_map_ordinary *ordmap | |
119 | = linemap_check_ordinary (insertion_point_map); | |
120 | expanded_location exploc_insertion_point = expand_location (insertion_point); | |
121 | location_t start_of_line | |
122 | = linemap_position_for_line_and_column (line_table, ordmap, | |
123 | exploc_insertion_point.line, 1); | |
124 | *out_start_of_line = start_of_line; | |
125 | return true; | |
126 | } | |
127 | ||
128 | /* Add a fix-it hint suggesting the insertion of CONTENT before | |
129 | INSERTION_POINT. | |
130 | ||
131 | Attempt to handle formatting: if INSERTION_POINT is the first thing on | |
132 | its line, and INDENT is sufficiently sane, then add CONTENT on its own | |
133 | line, using the indentation of INDENT. | |
134 | Otherwise, add CONTENT directly before INSERTION_POINT. | |
135 | ||
136 | For example, adding "CONTENT;" with the closing brace as the insertion | |
137 | point and "INDENT;" as the indentation point: | |
138 | ||
139 | if () | |
140 | { | |
141 | INDENT; | |
142 | } | |
143 | ||
144 | would lead to: | |
145 | ||
146 | if () | |
147 | { | |
148 | INDENT; | |
149 | CONTENT; | |
150 | } | |
151 | ||
152 | but adding it to: | |
153 | ||
154 | if () {INDENT;} | |
155 | ||
156 | would lead to: | |
157 | ||
158 | if () {INDENT;CONTENT;} | |
159 | */ | |
160 | ||
161 | void | |
162 | gcc_rich_location::add_fixit_insert_formatted (const char *content, | |
163 | location_t insertion_point, | |
164 | location_t indent) | |
165 | { | |
166 | location_t start_of_line; | |
1bdd665a DM |
167 | if (use_new_line (global_dc->get_file_cache (), |
168 | insertion_point, indent, &start_of_line)) | |
1a3a7b4e DM |
169 | { |
170 | /* Add CONTENT on its own line, using the indentation of INDENT. */ | |
171 | ||
172 | /* Generate an insertion string, indenting by the amount INDENT | |
173 | was indented. */ | |
174 | int indent_column = LOCATION_COLUMN (get_start (indent)); | |
175 | pretty_printer tmp_pp; | |
176 | pretty_printer *pp = &tmp_pp; | |
177 | /* Columns are 1-based. */ | |
178 | for (int column = 1; column < indent_column; ++column) | |
179 | pp_space (pp); | |
180 | pp_string (pp, content); | |
181 | pp_newline (pp); | |
182 | ||
183 | add_fixit_insert_before (start_of_line, pp_formatted_text (pp)); | |
184 | } | |
185 | else | |
186 | add_fixit_insert_before (insertion_point, content); | |
187 | } | |
a14feb3c DM |
188 | |
189 | /* Implementation of range_label::get_text for | |
190 | maybe_range_label_for_tree_type_mismatch. | |
191 | ||
192 | If both expressions are non-NULL, then generate text describing | |
193 | the first expression's type (using the other expression's type | |
194 | for comparison, analogous to %H and %I in the C++ frontend, but | |
195 | on expressions rather than types). */ | |
196 | ||
197 | label_text | |
198 | maybe_range_label_for_tree_type_mismatch::get_text (unsigned range_idx) const | |
199 | { | |
200 | if (m_expr == NULL_TREE | |
201 | || !EXPR_P (m_expr)) | |
d68f5d45 | 202 | return label_text::borrow (NULL); |
a14feb3c DM |
203 | tree expr_type = TREE_TYPE (m_expr); |
204 | ||
205 | tree other_type = NULL_TREE; | |
18633106 | 206 | if (m_other_expr && EXPR_P (m_other_expr)) |
a14feb3c DM |
207 | other_type = TREE_TYPE (m_other_expr); |
208 | ||
209 | range_label_for_type_mismatch inner (expr_type, other_type); | |
210 | return inner.get_text (range_idx); | |
211 | } | |
212 | ||
213 | /* binary_op_rich_location's ctor. | |
214 | ||
215 | If use_operator_loc_p (LOC, ARG0, ARG1), then attempt to make a 3-location | |
216 | rich_location of the form: | |
217 | ||
218 | arg_0 op arg_1 | |
219 | ~~~~~ ^~ ~~~~~ | |
220 | | | | |
221 | | arg1 type | |
222 | arg0 type | |
223 | ||
224 | labelling the types of the arguments if SHOW_TYPES is true. | |
225 | ||
226 | Otherwise, make a 1-location rich_location using the compound | |
227 | location within LOC: | |
228 | ||
229 | arg_0 op arg_1 | |
230 | ~~~~~~^~~~~~~~ | |
231 | ||
232 | for which we can't label the types. */ | |
233 | ||
234 | binary_op_rich_location::binary_op_rich_location (const op_location_t &loc, | |
235 | tree arg0, tree arg1, | |
236 | bool show_types) | |
237 | : gcc_rich_location (loc.m_combined_loc), | |
238 | m_label_for_arg0 (arg0, arg1), | |
239 | m_label_for_arg1 (arg1, arg0) | |
240 | { | |
241 | /* Default (above) to using the combined loc. | |
242 | Potentially override it here: if we have location information for the | |
243 | operator and for both arguments, then split them all out. | |
244 | Alternatively, override it if we don't have the combined location. */ | |
245 | if (use_operator_loc_p (loc, arg0, arg1)) | |
246 | { | |
247 | set_range (0, loc.m_operator_loc, SHOW_RANGE_WITH_CARET); | |
248 | maybe_add_expr (arg0, show_types ? &m_label_for_arg0 : NULL); | |
249 | maybe_add_expr (arg1, show_types ? &m_label_for_arg1 : NULL); | |
250 | } | |
251 | } | |
252 | ||
253 | /* Determine if binary_op_rich_location's ctor should attempt to make | |
254 | a 3-location rich_location (the location of the operator and of | |
255 | the 2 arguments), or fall back to a 1-location rich_location showing | |
256 | just the combined location of the operation as a whole. */ | |
257 | ||
258 | bool | |
259 | binary_op_rich_location::use_operator_loc_p (const op_location_t &loc, | |
260 | tree arg0, tree arg1) | |
261 | { | |
262 | /* If we don't have a combined location, then use the operator location, | |
263 | and try to add ranges for the operators. */ | |
264 | if (loc.m_combined_loc == UNKNOWN_LOCATION) | |
265 | return true; | |
266 | ||
267 | /* If we don't have the operator location, then use the | |
268 | combined location. */ | |
269 | if (loc.m_operator_loc == UNKNOWN_LOCATION) | |
270 | return false; | |
271 | ||
272 | /* We have both operator location and combined location: only use the | |
273 | operator location if we have locations for both arguments. */ | |
274 | return (EXPR_HAS_LOCATION (arg0) | |
275 | && EXPR_HAS_LOCATION (arg1)); | |
276 | } |