Branch data Line data Source code
1 : : /* Implementation of gcc_rich_location class
2 : : Copyright (C) 2014-2025 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 : : #include "diagnostics/file-cache.h"
41 : :
42 : : /* Add a range to the rich_location, covering expression EXPR,
43 : : using LABEL if non-NULL. */
44 : :
45 : : void
46 : 1073 : gcc_rich_location::add_expr (tree expr,
47 : : range_label *label,
48 : : const char *highlight_color)
49 : : {
50 : 1073 : gcc_assert (expr);
51 : :
52 : 1073 : if (CAN_HAVE_RANGE_P (expr))
53 : 1073 : add_range (EXPR_LOCATION (expr), SHOW_RANGE_WITHOUT_CARET, label,
54 : : highlight_color);
55 : 1073 : }
56 : :
57 : : /* If T is an expression, add a range for it to the rich_location,
58 : : using LABEL if non-NULL. */
59 : :
60 : : void
61 : 1722 : gcc_rich_location::maybe_add_expr (tree t, range_label *label,
62 : : const char *highlight_color)
63 : : {
64 : 1722 : if (EXPR_P (t))
65 : 1065 : add_expr (t, label, highlight_color);
66 : 1722 : }
67 : :
68 : : /* Add a fixit hint suggesting replacing the range at MISSPELLED_TOKEN_LOC
69 : : with the identifier HINT_ID. */
70 : :
71 : : void
72 : 67 : gcc_rich_location::add_fixit_misspelled_id (location_t misspelled_token_loc,
73 : : tree hint_id)
74 : : {
75 : 67 : gcc_assert (TREE_CODE (hint_id) == IDENTIFIER_NODE);
76 : :
77 : 67 : add_fixit_replace (misspelled_token_loc, IDENTIFIER_POINTER (hint_id));
78 : 67 : }
79 : :
80 : : /* Return true if there is nothing on LOC's line before LOC. */
81 : :
82 : : static bool
83 : 11 : blank_line_before_p (diagnostics::file_cache &fc,
84 : : location_t loc)
85 : : {
86 : 11 : expanded_location exploc = expand_location (loc);
87 : 11 : diagnostics::char_span line = fc.get_source_line (exploc.file, exploc.line);
88 : 11 : if (!line)
89 : : return false;
90 : 11 : if (line.length () < (size_t)exploc.column)
91 : : return false;
92 : : /* Columns are 1-based. */
93 : 31 : for (int column = 1; column < exploc.column; ++column)
94 : 21 : if (!ISSPACE (line[column - 1]))
95 : : return false;
96 : : return true;
97 : : }
98 : :
99 : : /* Subroutine of gcc_rich_location::add_fixit_insert_formatted.
100 : : Return true if we should add the content on its own line,
101 : : false otherwise.
102 : : If true is returned then *OUT_START_OF_LINE is written to. */
103 : :
104 : : static bool
105 : 20 : use_new_line (diagnostics::file_cache &fc,
106 : : location_t insertion_point, location_t indent,
107 : : location_t *out_start_of_line)
108 : : {
109 : 20 : if (indent == UNKNOWN_LOCATION)
110 : : return false;
111 : 11 : const line_map *indent_map = linemap_lookup (line_table, indent);
112 : 11 : if (linemap_macro_expansion_map_p (indent_map))
113 : : return false;
114 : :
115 : 11 : if (!blank_line_before_p (fc, insertion_point))
116 : : return false;
117 : :
118 : : /* Locate the start of the line containing INSERTION_POINT. */
119 : 10 : const line_map *insertion_point_map
120 : 10 : = linemap_lookup (line_table, insertion_point);
121 : 10 : if (linemap_macro_expansion_map_p (insertion_point_map))
122 : : return false;
123 : 10 : const line_map_ordinary *ordmap
124 : 10 : = linemap_check_ordinary (insertion_point_map);
125 : 10 : expanded_location exploc_insertion_point = expand_location (insertion_point);
126 : 10 : location_t start_of_line
127 : 20 : = linemap_position_for_line_and_column (line_table, ordmap,
128 : 10 : exploc_insertion_point.line, 1);
129 : 10 : *out_start_of_line = start_of_line;
130 : 10 : return true;
131 : : }
132 : :
133 : : /* Add a fix-it hint suggesting the insertion of CONTENT before
134 : : INSERTION_POINT.
135 : :
136 : : Attempt to handle formatting: if INSERTION_POINT is the first thing on
137 : : its line, and INDENT is sufficiently sane, then add CONTENT on its own
138 : : line, using the indentation of INDENT.
139 : : Otherwise, add CONTENT directly before INSERTION_POINT.
140 : :
141 : : For example, adding "CONTENT;" with the closing brace as the insertion
142 : : point and "INDENT;" as the indentation point:
143 : :
144 : : if ()
145 : : {
146 : : INDENT;
147 : : }
148 : :
149 : : would lead to:
150 : :
151 : : if ()
152 : : {
153 : : INDENT;
154 : : CONTENT;
155 : : }
156 : :
157 : : but adding it to:
158 : :
159 : : if () {INDENT;}
160 : :
161 : : would lead to:
162 : :
163 : : if () {INDENT;CONTENT;}
164 : : */
165 : :
166 : : void
167 : 20 : gcc_rich_location::add_fixit_insert_formatted (const char *content,
168 : : location_t insertion_point,
169 : : location_t indent)
170 : : {
171 : 20 : location_t start_of_line;
172 : 20 : if (use_new_line (global_dc->get_file_cache (),
173 : : insertion_point, indent, &start_of_line))
174 : : {
175 : : /* Add CONTENT on its own line, using the indentation of INDENT. */
176 : :
177 : : /* Generate an insertion string, indenting by the amount INDENT
178 : : was indented. */
179 : 10 : int indent_column = LOCATION_COLUMN (get_start (indent));
180 : 10 : pretty_printer tmp_pp;
181 : 10 : pretty_printer *pp = &tmp_pp;
182 : : /* Columns are 1-based. */
183 : 48 : for (int column = 1; column < indent_column; ++column)
184 : 38 : pp_space (pp);
185 : 10 : pp_string (pp, content);
186 : 10 : pp_newline (pp);
187 : :
188 : 10 : add_fixit_insert_before (start_of_line, pp_formatted_text (pp));
189 : 10 : }
190 : : else
191 : 10 : add_fixit_insert_before (insertion_point, content);
192 : 20 : }
|