]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/analyzer/pending-diagnostic.cc
5e95edd689be69d54b0991b4b4c4781f39e3aab3
[thirdparty/gcc.git] / gcc / analyzer / pending-diagnostic.cc
1 /* Classes for analyzer diagnostics.
2 Copyright (C) 2019-2025 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #include "analyzer/common.h"
22
23 #include "diagnostic-event-id.h"
24 #include "cpplib.h"
25 #include "digraph.h"
26 #include "ordered-hash-map.h"
27 #include "cfg.h"
28 #include "gimple-iterator.h"
29 #include "cgraph.h"
30
31 #include "analyzer/analyzer-logging.h"
32 #include "analyzer/sm.h"
33 #include "analyzer/sm.h"
34 #include "analyzer/pending-diagnostic.h"
35 #include "analyzer/diagnostic-manager.h"
36 #include "analyzer/call-string.h"
37 #include "analyzer/program-point.h"
38 #include "analyzer/store.h"
39 #include "analyzer/region-model.h"
40 #include "analyzer/supergraph.h"
41 #include "analyzer/program-state.h"
42 #include "analyzer/exploded-graph.h"
43 #include "analyzer/checker-path.h"
44
45 #if ENABLE_ANALYZER
46
47 namespace ana {
48
49 /* struct interesting_t. */
50
51 /* Mark the creation of REG as being interesting. */
52
53 void
54 interesting_t::add_region_creation (const region *reg)
55 {
56 gcc_assert (reg);
57 m_region_creation.safe_push (reg);
58 }
59
60 void
61 interesting_t::dump_to_pp (pretty_printer *pp, bool simple) const
62 {
63 pp_string (pp, "{ region creation: [");
64 unsigned i;
65 const region *reg;
66 FOR_EACH_VEC_ELT (m_region_creation, i, reg)
67 {
68 if (i > 0)
69 pp_string (pp, ", ");
70 reg->dump_to_pp (pp, simple);
71 }
72 pp_string (pp, "]}");
73 }
74
75 /* class diagnostic_emission_context. */
76
77 /* Get the pending_diagnostic being emitted. */
78
79 const pending_diagnostic &
80 diagnostic_emission_context::get_pending_diagnostic () const
81 {
82 return *m_sd.m_d.get ();
83 }
84
85 /* Emit a warning, using the rich_location, metadata, and the
86 pending_diagnostic's option. */
87
88 bool
89 diagnostic_emission_context::warn (const char *gmsgid, ...)
90 {
91 const pending_diagnostic &pd = get_pending_diagnostic ();
92 auto_diagnostic_group d;
93 va_list ap;
94 va_start (ap, gmsgid);
95 const bool result = emit_diagnostic_valist_meta (DK_WARNING,
96 &m_rich_loc, &m_metadata,
97 pd.get_controlling_option (),
98 gmsgid, &ap);
99 va_end (ap);
100 return result;
101 }
102
103 /* Emit a note, using the rich_location and metadata (and the
104 pending_diagnostic's option). */
105
106 void
107 diagnostic_emission_context::inform (const char *gmsgid, ...)
108 {
109 const pending_diagnostic &pd = get_pending_diagnostic ();
110 auto_diagnostic_group d;
111 va_list ap;
112 va_start (ap, gmsgid);
113 emit_diagnostic_valist_meta (DK_NOTE,
114 &m_rich_loc, &m_metadata,
115 pd.get_controlling_option (),
116 gmsgid, &ap);
117 va_end (ap);
118 }
119
120 /* Return true if T1 and T2 are "the same" for the purposes of
121 diagnostic deduplication. */
122
123 bool
124 pending_diagnostic::same_tree_p (tree t1, tree t2)
125 {
126 return simple_cst_equal (t1, t2) == 1;
127 }
128
129 /* Return true iff IDENT is STR. */
130
131 static bool
132 ht_ident_eq (ht_identifier ident, const char *str)
133 {
134 return (strlen (str) == ident.len
135 && 0 == strcmp (str, (const char *)ident.str));
136 }
137
138 /* Return true if we should show the expansion location rather than unwind
139 within MACRO. */
140
141 static bool
142 fixup_location_in_macro_p (cpp_hashnode *macro)
143 {
144 ht_identifier ident = macro->ident;
145
146 /* Don't unwind inside "alloca" macro, so that we don't suppress warnings
147 from it (due to being in system headers). */
148 if (ht_ident_eq (ident, "alloca"))
149 return true;
150
151 /* Don't unwind inside <stdarg.h> macros, so that we don't suppress warnings
152 from them (due to being in system headers). */
153 if (ht_ident_eq (ident, "va_start")
154 || ht_ident_eq (ident, "va_copy")
155 || ht_ident_eq (ident, "va_arg")
156 || ht_ident_eq (ident, "va_end"))
157 return true;
158 return false;
159 }
160
161 /* Base implementation of pending_diagnostic::fixup_location.
162 Don't unwind inside macros for which fixup_location_in_macro_p is true. */
163
164 location_t
165 pending_diagnostic::fixup_location (location_t loc, bool) const
166 {
167 if (linemap_location_from_macro_expansion_p (line_table, loc))
168 {
169 line_map *map
170 = const_cast <line_map *> (linemap_lookup (line_table, loc));
171 const line_map_macro *macro_map = linemap_check_macro (map);
172 if (fixup_location_in_macro_p (macro_map->macro))
173 loc = linemap_resolve_location (line_table, loc,
174 LRK_MACRO_EXPANSION_POINT, nullptr);
175 }
176 return loc;
177 }
178
179 /* Base implementation of pending_diagnostic::add_function_entry_event.
180 Add a function_entry_event to EMISSION_PATH. */
181
182 void
183 pending_diagnostic::add_function_entry_event (const exploded_edge &eedge,
184 checker_path *emission_path)
185 {
186 const exploded_node *dst_node = eedge.m_dest;
187 const program_point &dst_point = dst_node->get_point ();
188 const program_state &dst_state = dst_node->get_state ();
189 emission_path->add_event
190 (std::make_unique<function_entry_event> (dst_point,
191 dst_state));
192 }
193
194 /* Base implementation of pending_diagnostic::add_call_event.
195 Add a call_event to EMISSION_PATH. */
196
197 void
198 pending_diagnostic::add_call_event (const exploded_edge &eedge,
199 checker_path *emission_path)
200 {
201 const exploded_node *src_node = eedge.m_src;
202 const program_point &src_point = src_node->get_point ();
203 const int src_stack_depth = src_point.get_stack_depth ();
204 const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
205 emission_path->add_event
206 (std::make_unique<call_event> (eedge,
207 event_loc_info (last_stmt
208 ? last_stmt->location
209 : UNKNOWN_LOCATION,
210 src_point.get_fndecl (),
211 src_stack_depth)));
212 }
213
214 /* Base implementation of pending_diagnostic::add_region_creation_events.
215 See the comment for class region_creation_event. */
216
217 void
218 pending_diagnostic::add_region_creation_events (const region *reg,
219 tree capacity,
220 const event_loc_info &loc_info,
221 checker_path &emission_path)
222 {
223 emission_path.add_event
224 (std::make_unique<region_creation_event_memory_space>
225 (reg->get_memory_space (),
226 loc_info));
227
228 if (capacity)
229 emission_path.add_event
230 (std::make_unique<region_creation_event_capacity> (capacity, loc_info));
231 }
232
233 /* Base implementation of pending_diagnostic::add_final_event.
234 Add a warning_event to the end of EMISSION_PATH. */
235
236 void
237 pending_diagnostic::add_final_event (const state_machine *sm,
238 const exploded_node *enode,
239 const event_loc_info &loc_info,
240 tree var, state_machine::state_t state,
241 checker_path *emission_path)
242 {
243 emission_path->add_event
244 (std::make_unique<warning_event>
245 (loc_info,
246 enode,
247 sm, var, state,
248 get_final_state ()));
249 }
250
251 } // namespace ana
252
253 #endif /* #if ENABLE_ANALYZER */