Line data Source code
1 : /* Implementation of gcc_rich_location class
2 : Copyright (C) 2014-2026 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 1081 : gcc_rich_location::add_expr (tree expr,
47 : range_label *label,
48 : const char *highlight_color)
49 : {
50 1081 : gcc_assert (expr);
51 :
52 1081 : if (CAN_HAVE_RANGE_P (expr))
53 1081 : add_range (EXPR_LOCATION (expr), SHOW_RANGE_WITHOUT_CARET, label,
54 : highlight_color);
55 1081 : }
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 1730 : gcc_rich_location::maybe_add_expr (tree t, range_label *label,
62 : const char *highlight_color)
63 : {
64 1730 : if (EXPR_P (t))
65 1073 : add_expr (t, label, highlight_color);
66 1730 : }
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 : }
|