Branch data Line data Source code
1 : : /* Implementation of gcc_rich_location class
2 : : Copyright (C) 2014-2024 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 "tm.h"
24 : : #include "rtl.h"
25 : : #include "hash-set.h"
26 : : #include "vec.h"
27 : : #include "input.h"
28 : : #include "alias.h"
29 : : #include "symtab.h"
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 : :
41 : : /* Add a range to the rich_location, covering expression EXPR,
42 : : using LABEL if non-NULL. */
43 : :
44 : : void
45 : 1168 : gcc_rich_location::add_expr (tree expr, range_label *label)
46 : : {
47 : 1168 : gcc_assert (expr);
48 : :
49 : 1168 : if (CAN_HAVE_RANGE_P (expr))
50 : 1168 : add_range (EXPR_LOCATION (expr), SHOW_RANGE_WITHOUT_CARET, label);
51 : 1168 : }
52 : :
53 : : /* If T is an expression, add a range for it to the rich_location,
54 : : using LABEL if non-NULL. */
55 : :
56 : : void
57 : 1816 : gcc_rich_location::maybe_add_expr (tree t, range_label *label)
58 : : {
59 : 1816 : if (EXPR_P (t))
60 : 1160 : add_expr (t, label);
61 : 1816 : }
62 : :
63 : : /* Add a fixit hint suggesting replacing the range at MISSPELLED_TOKEN_LOC
64 : : with the identifier HINT_ID. */
65 : :
66 : : void
67 : 84 : gcc_rich_location::add_fixit_misspelled_id (location_t misspelled_token_loc,
68 : : tree hint_id)
69 : : {
70 : 84 : gcc_assert (TREE_CODE (hint_id) == IDENTIFIER_NODE);
71 : :
72 : 84 : add_fixit_replace (misspelled_token_loc, IDENTIFIER_POINTER (hint_id));
73 : 84 : }
74 : :
75 : : /* Return true if there is nothing on LOC's line before LOC. */
76 : :
77 : : static bool
78 : 14 : blank_line_before_p (file_cache &fc,
79 : : location_t loc)
80 : : {
81 : 14 : expanded_location exploc = expand_location (loc);
82 : 14 : char_span line = fc.get_source_line (exploc.file, exploc.line);
83 : 14 : if (!line)
84 : : return false;
85 : 14 : if (line.length () < (size_t)exploc.column)
86 : : return false;
87 : : /* Columns are 1-based. */
88 : 40 : for (int column = 1; column < exploc.column; ++column)
89 : 27 : 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
100 : 26 : use_new_line (file_cache &fc,
101 : : location_t insertion_point, location_t indent,
102 : : location_t *out_start_of_line)
103 : : {
104 : 26 : if (indent == UNKNOWN_LOCATION)
105 : : return false;
106 : 14 : const line_map *indent_map = linemap_lookup (line_table, indent);
107 : 14 : if (linemap_macro_expansion_map_p (indent_map))
108 : : return false;
109 : :
110 : 14 : if (!blank_line_before_p (fc, insertion_point))
111 : : return false;
112 : :
113 : : /* Locate the start of the line containing INSERTION_POINT. */
114 : 13 : const line_map *insertion_point_map
115 : 13 : = linemap_lookup (line_table, insertion_point);
116 : 13 : if (linemap_macro_expansion_map_p (insertion_point_map))
117 : : return false;
118 : 13 : const line_map_ordinary *ordmap
119 : 13 : = linemap_check_ordinary (insertion_point_map);
120 : 13 : expanded_location exploc_insertion_point = expand_location (insertion_point);
121 : 13 : location_t start_of_line
122 : 26 : = linemap_position_for_line_and_column (line_table, ordmap,
123 : 13 : exploc_insertion_point.line, 1);
124 : 13 : *out_start_of_line = start_of_line;
125 : 13 : 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 : 26 : gcc_rich_location::add_fixit_insert_formatted (const char *content,
163 : : location_t insertion_point,
164 : : location_t indent)
165 : : {
166 : 26 : location_t start_of_line;
167 : 26 : if (use_new_line (global_dc->get_file_cache (),
168 : : insertion_point, indent, &start_of_line))
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 : 13 : int indent_column = LOCATION_COLUMN (get_start (indent));
175 : 13 : pretty_printer tmp_pp;
176 : 13 : pretty_printer *pp = &tmp_pp;
177 : : /* Columns are 1-based. */
178 : 63 : for (int column = 1; column < indent_column; ++column)
179 : 50 : pp_space (pp);
180 : 13 : pp_string (pp, content);
181 : 13 : pp_newline (pp);
182 : :
183 : 13 : add_fixit_insert_before (start_of_line, pp_formatted_text (pp));
184 : 13 : }
185 : : else
186 : 13 : add_fixit_insert_before (insertion_point, content);
187 : 26 : }
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 : 70 : maybe_range_label_for_tree_type_mismatch::get_text (unsigned range_idx) const
199 : : {
200 : 70 : if (m_expr == NULL_TREE
201 : 70 : || !EXPR_P (m_expr))
202 : 0 : return label_text::borrow (NULL);
203 : 70 : tree expr_type = TREE_TYPE (m_expr);
204 : :
205 : 70 : tree other_type = NULL_TREE;
206 : 70 : if (m_other_expr && EXPR_P (m_other_expr))
207 : 68 : other_type = TREE_TYPE (m_other_expr);
208 : :
209 : 70 : range_label_for_type_mismatch inner (expr_type, other_type);
210 : 70 : return inner.get_text (range_idx);
211 : 70 : }
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 : 1118 : binary_op_rich_location::binary_op_rich_location (const op_location_t &loc,
235 : : tree arg0, tree arg1,
236 : 1118 : bool show_types)
237 : 1118 : : gcc_rich_location (loc.m_combined_loc),
238 : 1118 : m_label_for_arg0 (arg0, arg1),
239 : 1118 : 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 : 1118 : if (use_operator_loc_p (loc, arg0, arg1))
246 : : {
247 : 882 : set_range (0, loc.m_operator_loc, SHOW_RANGE_WITH_CARET);
248 : 882 : maybe_add_expr (arg0, show_types ? &m_label_for_arg0 : NULL);
249 : 882 : maybe_add_expr (arg1, show_types ? &m_label_for_arg1 : NULL);
250 : : }
251 : 1118 : }
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 : 1118 : 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 : 1118 : 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 : 608 : 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 : 406 : return (EXPR_HAS_LOCATION (arg0)
275 : 387 : && EXPR_HAS_LOCATION (arg1));
276 : : }
|