]>
Commit | Line | Data |
---|---|---|
ebedc9a3 | 1 | /* Implementation of gcc_rich_location class |
aeee4812 | 2 | Copyright (C) 2014-2023 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 | |
78 | blank_line_before_p (location_t loc) | |
79 | { | |
80 | expanded_location exploc = expand_location (loc); | |
81 | char_span line = location_get_source_line (exploc.file, exploc.line); | |
82 | if (!line) | |
83 | return false; | |
84 | if (line.length () < (size_t)exploc.column) | |
85 | return false; | |
86 | /* Columns are 1-based. */ | |
87 | for (int column = 1; column < exploc.column; ++column) | |
88 | if (!ISSPACE (line[column - 1])) | |
89 | return false; | |
90 | return true; | |
91 | } | |
92 | ||
93 | /* Subroutine of gcc_rich_location::add_fixit_insert_formatted. | |
94 | Return true if we should add the content on its own line, | |
95 | false otherwise. | |
96 | If true is returned then *OUT_START_OF_LINE is written to. */ | |
97 | ||
98 | static bool | |
99 | use_new_line (location_t insertion_point, location_t indent, | |
100 | location_t *out_start_of_line) | |
101 | { | |
102 | if (indent == UNKNOWN_LOCATION) | |
103 | return false; | |
104 | const line_map *indent_map = linemap_lookup (line_table, indent); | |
105 | if (linemap_macro_expansion_map_p (indent_map)) | |
106 | return false; | |
107 | ||
108 | if (!blank_line_before_p (insertion_point)) | |
109 | return false; | |
110 | ||
111 | /* Locate the start of the line containing INSERTION_POINT. */ | |
112 | const line_map *insertion_point_map | |
113 | = linemap_lookup (line_table, insertion_point); | |
114 | if (linemap_macro_expansion_map_p (insertion_point_map)) | |
115 | return false; | |
116 | const line_map_ordinary *ordmap | |
117 | = linemap_check_ordinary (insertion_point_map); | |
118 | expanded_location exploc_insertion_point = expand_location (insertion_point); | |
119 | location_t start_of_line | |
120 | = linemap_position_for_line_and_column (line_table, ordmap, | |
121 | exploc_insertion_point.line, 1); | |
122 | *out_start_of_line = start_of_line; | |
123 | return true; | |
124 | } | |
125 | ||
126 | /* Add a fix-it hint suggesting the insertion of CONTENT before | |
127 | INSERTION_POINT. | |
128 | ||
129 | Attempt to handle formatting: if INSERTION_POINT is the first thing on | |
130 | its line, and INDENT is sufficiently sane, then add CONTENT on its own | |
131 | line, using the indentation of INDENT. | |
132 | Otherwise, add CONTENT directly before INSERTION_POINT. | |
133 | ||
134 | For example, adding "CONTENT;" with the closing brace as the insertion | |
135 | point and "INDENT;" as the indentation point: | |
136 | ||
137 | if () | |
138 | { | |
139 | INDENT; | |
140 | } | |
141 | ||
142 | would lead to: | |
143 | ||
144 | if () | |
145 | { | |
146 | INDENT; | |
147 | CONTENT; | |
148 | } | |
149 | ||
150 | but adding it to: | |
151 | ||
152 | if () {INDENT;} | |
153 | ||
154 | would lead to: | |
155 | ||
156 | if () {INDENT;CONTENT;} | |
157 | */ | |
158 | ||
159 | void | |
160 | gcc_rich_location::add_fixit_insert_formatted (const char *content, | |
161 | location_t insertion_point, | |
162 | location_t indent) | |
163 | { | |
164 | location_t start_of_line; | |
165 | if (use_new_line (insertion_point, indent, &start_of_line)) | |
166 | { | |
167 | /* Add CONTENT on its own line, using the indentation of INDENT. */ | |
168 | ||
169 | /* Generate an insertion string, indenting by the amount INDENT | |
170 | was indented. */ | |
171 | int indent_column = LOCATION_COLUMN (get_start (indent)); | |
172 | pretty_printer tmp_pp; | |
173 | pretty_printer *pp = &tmp_pp; | |
174 | /* Columns are 1-based. */ | |
175 | for (int column = 1; column < indent_column; ++column) | |
176 | pp_space (pp); | |
177 | pp_string (pp, content); | |
178 | pp_newline (pp); | |
179 | ||
180 | add_fixit_insert_before (start_of_line, pp_formatted_text (pp)); | |
181 | } | |
182 | else | |
183 | add_fixit_insert_before (insertion_point, content); | |
184 | } | |
a14feb3c DM |
185 | |
186 | /* Implementation of range_label::get_text for | |
187 | maybe_range_label_for_tree_type_mismatch. | |
188 | ||
189 | If both expressions are non-NULL, then generate text describing | |
190 | the first expression's type (using the other expression's type | |
191 | for comparison, analogous to %H and %I in the C++ frontend, but | |
192 | on expressions rather than types). */ | |
193 | ||
194 | label_text | |
195 | maybe_range_label_for_tree_type_mismatch::get_text (unsigned range_idx) const | |
196 | { | |
197 | if (m_expr == NULL_TREE | |
198 | || !EXPR_P (m_expr)) | |
d68f5d45 | 199 | return label_text::borrow (NULL); |
a14feb3c DM |
200 | tree expr_type = TREE_TYPE (m_expr); |
201 | ||
202 | tree other_type = NULL_TREE; | |
ca2007a9 | 203 | if (CAN_HAVE_LOCATION_P (m_other_expr)) |
a14feb3c DM |
204 | other_type = TREE_TYPE (m_other_expr); |
205 | ||
206 | range_label_for_type_mismatch inner (expr_type, other_type); | |
207 | return inner.get_text (range_idx); | |
208 | } | |
209 | ||
210 | /* binary_op_rich_location's ctor. | |
211 | ||
212 | If use_operator_loc_p (LOC, ARG0, ARG1), then attempt to make a 3-location | |
213 | rich_location of the form: | |
214 | ||
215 | arg_0 op arg_1 | |
216 | ~~~~~ ^~ ~~~~~ | |
217 | | | | |
218 | | arg1 type | |
219 | arg0 type | |
220 | ||
221 | labelling the types of the arguments if SHOW_TYPES is true. | |
222 | ||
223 | Otherwise, make a 1-location rich_location using the compound | |
224 | location within LOC: | |
225 | ||
226 | arg_0 op arg_1 | |
227 | ~~~~~~^~~~~~~~ | |
228 | ||
229 | for which we can't label the types. */ | |
230 | ||
231 | binary_op_rich_location::binary_op_rich_location (const op_location_t &loc, | |
232 | tree arg0, tree arg1, | |
233 | bool show_types) | |
234 | : gcc_rich_location (loc.m_combined_loc), | |
235 | m_label_for_arg0 (arg0, arg1), | |
236 | m_label_for_arg1 (arg1, arg0) | |
237 | { | |
238 | /* Default (above) to using the combined loc. | |
239 | Potentially override it here: if we have location information for the | |
240 | operator and for both arguments, then split them all out. | |
241 | Alternatively, override it if we don't have the combined location. */ | |
242 | if (use_operator_loc_p (loc, arg0, arg1)) | |
243 | { | |
244 | set_range (0, loc.m_operator_loc, SHOW_RANGE_WITH_CARET); | |
245 | maybe_add_expr (arg0, show_types ? &m_label_for_arg0 : NULL); | |
246 | maybe_add_expr (arg1, show_types ? &m_label_for_arg1 : NULL); | |
247 | } | |
248 | } | |
249 | ||
250 | /* Determine if binary_op_rich_location's ctor should attempt to make | |
251 | a 3-location rich_location (the location of the operator and of | |
252 | the 2 arguments), or fall back to a 1-location rich_location showing | |
253 | just the combined location of the operation as a whole. */ | |
254 | ||
255 | bool | |
256 | binary_op_rich_location::use_operator_loc_p (const op_location_t &loc, | |
257 | tree arg0, tree arg1) | |
258 | { | |
259 | /* If we don't have a combined location, then use the operator location, | |
260 | and try to add ranges for the operators. */ | |
261 | if (loc.m_combined_loc == UNKNOWN_LOCATION) | |
262 | return true; | |
263 | ||
264 | /* If we don't have the operator location, then use the | |
265 | combined location. */ | |
266 | if (loc.m_operator_loc == UNKNOWN_LOCATION) | |
267 | return false; | |
268 | ||
269 | /* We have both operator location and combined location: only use the | |
270 | operator location if we have locations for both arguments. */ | |
271 | return (EXPR_HAS_LOCATION (arg0) | |
272 | && EXPR_HAS_LOCATION (arg1)); | |
273 | } |