Branch data Line data Source code
1 : : /* Subclasses of diagnostics::paths::event 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 "gimple-pretty-print.h"
24 : : #include "sbitmap.h"
25 : : #include "ordered-hash-map.h"
26 : : #include "fold-const.h"
27 : : #include "gimple-iterator.h"
28 : : #include "inlining-iterator.h"
29 : : #include "tree-logical-location.h"
30 : : #include "diagnostics/sarif-sink.h"
31 : : #include "diagnostics/state-graphs.h"
32 : : #include "custom-sarif-properties/state-graphs.h"
33 : :
34 : : #include "analyzer/analyzer-logging.h"
35 : : #include "analyzer/sm.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/program-state.h"
41 : : #include "analyzer/checker-path.h"
42 : : #include "analyzer/supergraph.h"
43 : : #include "analyzer/pending-diagnostic.h"
44 : : #include "analyzer/diagnostic-manager.h"
45 : : #include "analyzer/constraint-manager.h"
46 : : #include "analyzer/checker-event.h"
47 : : #include "analyzer/exploded-graph.h"
48 : :
49 : : #if ENABLE_ANALYZER
50 : :
51 : : namespace ana {
52 : :
53 : : /* Get a string for EK. */
54 : :
55 : : const char *
56 : 81 : event_kind_to_string (enum event_kind ek)
57 : : {
58 : 81 : switch (ek)
59 : : {
60 : 0 : default:
61 : 0 : gcc_unreachable ();
62 : : case event_kind::debug:
63 : : return "debug";
64 : 0 : case event_kind::custom:
65 : 0 : return "custom";
66 : 0 : case event_kind::stmt:
67 : 0 : return "stmt";
68 : 12 : case event_kind::region_creation:
69 : 12 : return "region_creation";
70 : 4 : case event_kind::function_entry:
71 : 4 : return "function_entry";
72 : 20 : case event_kind::state_change:
73 : 20 : return "state_change";
74 : 10 : case event_kind::start_cfg_edge:
75 : 10 : return "start_cfg_edge";
76 : 10 : case event_kind::end_cfg_edge:
77 : 10 : return "end_cfg_edge";
78 : 0 : case event_kind::catch_:
79 : 0 : return "catch";
80 : 3 : case event_kind::call_edge:
81 : 3 : return "call_edge";
82 : 3 : case event_kind::return_edge:
83 : 3 : return "return_edge";
84 : 0 : case event_kind::start_consolidated_cfg_edges:
85 : 0 : return "start_consolidated_cfg_edges";
86 : 0 : case event_kind::end_consolidated_cfg_edges:
87 : 0 : return "end_consolidated_cfg_edges";
88 : 0 : case event_kind::inlined_call:
89 : 0 : return "inlined_call";
90 : 0 : case event_kind::setjmp_:
91 : 0 : return "setjmp";
92 : 0 : case event_kind::rewind_from_longjmp:
93 : 0 : return "rewind_from_longjmp";
94 : 0 : case event_kind::rewind_to_setjmp:
95 : 0 : return "rewind_to_setjmp";
96 : 0 : case event_kind::throw_:
97 : 0 : return "throw";
98 : 0 : case event_kind::unwind:
99 : 0 : return "unwind";
100 : 19 : case event_kind::warning:
101 : 19 : return "warning";
102 : : }
103 : : }
104 : :
105 : : /* class checker_event : public diagnostics::paths::event. */
106 : :
107 : : /* checker_event's ctor. */
108 : :
109 : 61283 : checker_event::checker_event (enum event_kind kind,
110 : 61283 : const event_loc_info &loc_info)
111 : 61283 : : m_path (nullptr),
112 : 61283 : m_kind (kind), m_loc (loc_info.m_loc),
113 : 61283 : m_original_fndecl (loc_info.m_fndecl),
114 : 61283 : m_effective_fndecl (loc_info.m_fndecl),
115 : 61283 : m_original_depth (loc_info.m_depth),
116 : 61283 : m_effective_depth (loc_info.m_depth),
117 : 61283 : m_pending_diagnostic (nullptr), m_emission_id (),
118 : : m_logical_loc
119 : 61283 : (tree_logical_location_manager::key_from_tree (loc_info.m_fndecl))
120 : : {
121 : : /* Update effective fndecl and depth if inlining has been recorded. */
122 : 61283 : if (flag_analyzer_undo_inlining)
123 : : {
124 : 61255 : inlining_info info (m_loc);
125 : 61255 : if (info.get_inner_fndecl ())
126 : : {
127 : 46490 : m_effective_fndecl = info.get_inner_fndecl ();
128 : 46490 : m_effective_depth += info.get_extra_frames ();
129 : 46490 : m_logical_loc
130 : 46490 : = tree_logical_location_manager::key_from_tree (m_effective_fndecl);
131 : : }
132 : : }
133 : 61283 : }
134 : :
135 : : /* No-op implementation of diagnostics::paths::event::get_meaning vfunc for
136 : : checker_event: checker events have no meaning by default. */
137 : :
138 : : diagnostics::paths::event::meaning
139 : 92 : checker_event::get_meaning () const
140 : : {
141 : 92 : return diagnostics::paths::event::meaning ();
142 : : }
143 : :
144 : : /* Implementation of diagnostics::paths::event::maybe_add_sarif_properties
145 : : for checker_event. */
146 : :
147 : : void
148 : 81 : checker_event::
149 : : maybe_add_sarif_properties (diagnostics::sarif_builder &builder,
150 : : diagnostics::sarif_object &thread_flow_loc_obj) const
151 : : {
152 : 81 : auto &props = thread_flow_loc_obj.get_or_create_properties ();
153 : : #define PROPERTY_PREFIX "gcc/analyzer/checker_event/"
154 : 162 : props.set (PROPERTY_PREFIX "emission_id",
155 : 81 : diagnostic_event_id_to_json (m_emission_id));
156 : 81 : props.set_string (PROPERTY_PREFIX "kind", event_kind_to_string (m_kind));
157 : :
158 : 81 : if (m_original_fndecl != m_effective_fndecl)
159 : 0 : props.set_logical_location
160 : 0 : (PROPERTY_PREFIX "original_fndecl",
161 : : builder,
162 : 0 : tree_logical_location_manager::key_from_tree (m_original_fndecl));
163 : :
164 : 81 : if (m_original_depth != m_effective_depth)
165 : 0 : props.set_integer (PROPERTY_PREFIX "original_depth", m_original_depth);
166 : : #undef PROPERTY_PREFIX
167 : 81 : }
168 : :
169 : : /* Dump this event to PP (for debugging/logging purposes). */
170 : :
171 : : void
172 : 0 : checker_event::dump (pretty_printer *pp) const
173 : : {
174 : 0 : pp_character (pp, '"');
175 : 0 : print_desc (*pp);
176 : 0 : pp_printf (pp, "\" (depth %i", m_effective_depth);
177 : :
178 : 0 : if (m_effective_depth != m_original_depth)
179 : 0 : pp_printf (pp, " corrected from %i",
180 : : m_original_depth);
181 : 0 : if (m_effective_fndecl)
182 : : {
183 : 0 : pp_printf (pp, ", fndecl %qE", m_effective_fndecl);
184 : 0 : if (m_effective_fndecl != m_original_fndecl)
185 : 0 : pp_printf (pp, " corrected from %qE", m_original_fndecl);
186 : : }
187 : 0 : pp_printf (pp, ", m_loc=%llx)",
188 : 0 : (unsigned long long) get_location ());
189 : 0 : }
190 : :
191 : : /* Dump this event to stderr (for debugging/logging purposes). */
192 : :
193 : : DEBUG_FUNCTION void
194 : 0 : checker_event::debug () const
195 : : {
196 : 0 : tree_dump_pretty_printer pp (stderr);
197 : 0 : dump (&pp);
198 : 0 : pp_newline (&pp);
199 : 0 : }
200 : :
201 : : /* Hook for being notified when this event has its final id EMISSION_ID
202 : : and is about to emitted for PD.
203 : :
204 : : Base implementation of checker_event::prepare_for_emission vfunc;
205 : : subclasses that override this should chain up to it.
206 : :
207 : : Record PD and EMISSION_ID, and call the print_desc vfunc, so that any
208 : : side-effects of the call to print_desc take place before
209 : : pending_diagnostic::emit is called.
210 : :
211 : : For example, state_change_event::print_desc can call
212 : : pending_diagnostic::describe_state_change; free_of_non_heap can use this
213 : : to tweak the message (TODO: would be neater to simply capture the
214 : : pertinent data within the sm-state). */
215 : :
216 : : void
217 : 17228 : checker_event::prepare_for_emission (checker_path *path,
218 : : pending_diagnostic *pd,
219 : : diagnostics::paths::event_id_t emission_id)
220 : : {
221 : 17228 : m_path = path;
222 : 17228 : m_pending_diagnostic = pd;
223 : 17228 : m_emission_id = emission_id;
224 : :
225 : 17228 : auto pp = global_dc->clone_printer ();
226 : 17228 : print_desc (*pp.get ());
227 : 17228 : }
228 : :
229 : : std::unique_ptr<diagnostics::digraphs::digraph>
230 : 28 : checker_event::maybe_make_diagnostic_state_graph (bool debug) const
231 : : {
232 : 28 : const program_state *state = get_program_state ();
233 : 28 : if (!state)
234 : 0 : return nullptr;
235 : :
236 : 28 : gcc_assert (m_path);
237 : 28 : const extrinsic_state &ext_state = m_path->get_ext_state ();
238 : :
239 : 28 : auto result = state->make_diagnostic_state_graph (ext_state);
240 : :
241 : 28 : if (debug)
242 : : {
243 : 27 : pretty_printer pp;
244 : 27 : text_art::theme *theme = global_dc->get_diagram_theme ();
245 : 27 : text_art::dump_to_pp (*state, theme, &pp);
246 : 27 : const json::string_property program_state_property
247 : : (custom_sarif_properties::state_graphs::graph::prefix,
248 : 27 : "analyzer/program_state/");
249 : 27 : result->set_property (program_state_property,
250 : : pp_formatted_text (&pp));
251 : 27 : }
252 : :
253 : 28 : return result;
254 : 28 : }
255 : :
256 : : /* class debug_event : public checker_event. */
257 : :
258 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
259 : : debug_event.
260 : : Use the saved string as the event's description. */
261 : :
262 : : void
263 : 0 : debug_event::print_desc (pretty_printer &pp) const
264 : : {
265 : 0 : pp_string (&pp, m_desc);
266 : 0 : }
267 : :
268 : : /* class precanned_custom_event : public custom_event. */
269 : :
270 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
271 : : precanned_custom_event.
272 : : Use the saved string as the event's description. */
273 : :
274 : : void
275 : 40 : precanned_custom_event::print_desc (pretty_printer &pp) const
276 : : {
277 : 40 : pp_string (&pp, m_desc);
278 : 40 : }
279 : :
280 : : /* class statement_event : public checker_event. */
281 : :
282 : : /* statement_event's ctor. */
283 : :
284 : 19517 : statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
285 : 19517 : const program_state &dst_state)
286 : : : checker_event (event_kind::stmt,
287 : 19517 : event_loc_info (gimple_location (stmt), fndecl, depth)),
288 : 19517 : m_stmt (stmt),
289 : 19517 : m_dst_state (dst_state)
290 : : {
291 : 19517 : }
292 : :
293 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
294 : : statement_event.
295 : : Use the statement's dump form as the event's description. */
296 : :
297 : : void
298 : 0 : statement_event::print_desc (pretty_printer &pp) const
299 : : {
300 : 0 : pp_string (&pp, "stmt: ");
301 : 0 : pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
302 : 0 : }
303 : :
304 : : /* class region_creation_event : public checker_event. */
305 : :
306 : 1539 : region_creation_event::region_creation_event (const event_loc_info &loc_info)
307 : 1539 : : checker_event (event_kind::region_creation, loc_info)
308 : : {
309 : 1539 : }
310 : :
311 : : /* The various region_creation_event subclasses' print_desc
312 : : implementations. */
313 : :
314 : : void
315 : 1184 : region_creation_event_memory_space::print_desc (pretty_printer &pp) const
316 : : {
317 : 1184 : switch (m_mem_space)
318 : : {
319 : 28 : default:
320 : 28 : pp_string (&pp, "region created here");
321 : 28 : return;
322 : 1058 : case MEMSPACE_STACK:
323 : 1058 : pp_string (&pp, "region created on stack here");
324 : 1058 : return;
325 : 98 : case MEMSPACE_HEAP:
326 : 98 : pp_string (&pp, "region created on heap here");
327 : 98 : return;
328 : : }
329 : : }
330 : :
331 : : void
332 : 1600 : region_creation_event_capacity::print_desc (pretty_printer &pp) const
333 : : {
334 : 1600 : gcc_assert (m_capacity);
335 : 1600 : if (TREE_CODE (m_capacity) == INTEGER_CST)
336 : : {
337 : 1404 : unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
338 : 1404 : return pp_printf_n (&pp,
339 : : hwi,
340 : : "capacity: %wu byte",
341 : : "capacity: %wu bytes",
342 : 1404 : hwi);
343 : : }
344 : : else
345 : 196 : return pp_printf (&pp, "capacity: %qE bytes", m_capacity);
346 : : }
347 : :
348 : : void
349 : 182 : region_creation_event_allocation_size::print_desc (pretty_printer &pp) const
350 : : {
351 : 182 : if (m_capacity)
352 : : {
353 : 174 : if (TREE_CODE (m_capacity) == INTEGER_CST)
354 : 118 : pp_printf_n (&pp,
355 : : tree_to_uhwi (m_capacity),
356 : : "allocated %E byte here",
357 : : "allocated %E bytes here",
358 : : m_capacity);
359 : : else
360 : 56 : pp_printf (&pp,
361 : : "allocated %qE bytes here",
362 : : m_capacity);
363 : : }
364 : 182 : pp_printf (&pp, "allocated here");
365 : 182 : }
366 : :
367 : : void
368 : 0 : region_creation_event_debug::print_desc (pretty_printer &pp) const
369 : : {
370 : 0 : pp_string (&pp, "region creation: ");
371 : 0 : m_reg->dump_to_pp (&pp, true);
372 : 0 : if (m_capacity)
373 : 0 : pp_printf (&pp, " capacity: %qE", m_capacity);
374 : 0 : }
375 : :
376 : : /* class function_entry_event : public checker_event. */
377 : :
378 : 5206 : function_entry_event::function_entry_event (const program_point &dst_point,
379 : 5206 : const program_state &state)
380 : : : checker_event (event_kind::function_entry,
381 : 5206 : event_loc_info (dst_point.get_supernode
382 : : ()->get_start_location (),
383 : : dst_point.get_fndecl (),
384 : 5206 : dst_point.get_stack_depth ())),
385 : 10412 : m_state (state)
386 : : {
387 : 5206 : }
388 : :
389 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
390 : : function_entry_event.
391 : :
392 : : Use a string such as "entry to 'foo'" as the event's description. */
393 : :
394 : : void
395 : 2802 : function_entry_event::print_desc (pretty_printer &pp) const
396 : : {
397 : 2802 : pp_printf (&pp, "entry to %qE", m_effective_fndecl);
398 : 2802 : }
399 : :
400 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
401 : : function entry. */
402 : :
403 : : diagnostics::paths::event::meaning
404 : 203 : function_entry_event::get_meaning () const
405 : : {
406 : 203 : return meaning (verb::enter, noun::function);
407 : : }
408 : :
409 : : /* class state_change_event : public checker_event. */
410 : :
411 : : /* state_change_event's ctor. */
412 : :
413 : 4723 : state_change_event::state_change_event (const supernode *node,
414 : : const gimple *stmt,
415 : : int stack_depth,
416 : : const state_machine &sm,
417 : : const svalue *sval,
418 : : state_machine::state_t from,
419 : : state_machine::state_t to,
420 : : const svalue *origin,
421 : : const program_state &dst_state,
422 : 4723 : const exploded_node *enode)
423 : : : checker_event (event_kind::state_change,
424 : 9446 : event_loc_info (stmt->location,
425 : 4723 : node->m_fun->decl,
426 : 4723 : stack_depth)),
427 : 4723 : m_node (node), m_stmt (stmt), m_sm (sm),
428 : 4723 : m_sval (sval), m_from (from), m_to (to),
429 : 4723 : m_origin (origin),
430 : 4723 : m_dst_state (dst_state),
431 : 4723 : m_enode (enode)
432 : : {
433 : 4723 : }
434 : :
435 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
436 : : state_change_event.
437 : :
438 : : Attempt to generate a nicer human-readable description.
439 : : For greatest precision-of-wording, give the pending diagnostic
440 : : a chance to describe this state change (in terms of the
441 : : diagnostic).
442 : : Note that we only have a pending_diagnostic set on the event once
443 : : the diagnostic is about to being emitted, so the description for
444 : : an event can change. */
445 : :
446 : : void
447 : 4552 : state_change_event::print_desc (pretty_printer &pp) const
448 : : {
449 : 4552 : if (m_pending_diagnostic)
450 : : {
451 : 4552 : region_model *model = m_dst_state.m_region_model;
452 : 4552 : tree var = model->get_representative_tree (m_sval);
453 : 4552 : tree origin = model->get_representative_tree (m_origin);
454 : 4552 : evdesc::state_change evd (var, origin,
455 : 4552 : m_from, m_to, m_emission_id, *this);
456 : 4552 : if (m_pending_diagnostic->describe_state_change (pp, evd))
457 : : {
458 : 4550 : if (flag_analyzer_verbose_state_changes)
459 : : {
460 : : /* Append debugging information about this event. */
461 : :
462 : 144 : if (var)
463 : 136 : pp_printf (&pp, " (state of %qE: ", var);
464 : : else
465 : 8 : pp_string (&pp, " (state: ");
466 : :
467 : 144 : pp_printf (&pp, "%qs -> %qs, ",
468 : 144 : m_from->get_name (),
469 : 144 : m_to->get_name ());
470 : :
471 : 144 : if (m_origin)
472 : 0 : pp_printf (&pp, "origin: %qE", origin);
473 : : else
474 : 144 : pp_string (&pp, "NULL origin");
475 : :
476 : : /* Get any "meaning" of event. */
477 : 144 : diagnostics::paths::event::meaning meaning = get_meaning ();
478 : 144 : pp_string (&pp, ", meaning: ");
479 : 144 : meaning.dump_to_pp (&pp);
480 : 144 : pp_string (&pp, ")");
481 : : }
482 : 4550 : return;
483 : : }
484 : : }
485 : :
486 : : /* Fallback description. */
487 : 2 : if (m_sval)
488 : : {
489 : 2 : label_text sval_desc = m_sval->get_desc ();
490 : 2 : pp_printf (&pp,
491 : : "state of %qs: %qs -> %qs",
492 : : sval_desc.get (),
493 : 2 : m_from->get_name (),
494 : 2 : m_to->get_name ());
495 : 2 : if (m_origin)
496 : : {
497 : 0 : label_text origin_desc = m_origin->get_desc ();
498 : 0 : pp_printf (&pp, " (origin: %qs)",
499 : : origin_desc.get ());
500 : 0 : }
501 : : else
502 : 2 : pp_string (&pp, " (NULL origin)");
503 : 2 : }
504 : : else
505 : : {
506 : 0 : gcc_assert (m_origin == nullptr);
507 : 0 : pp_printf (&pp,
508 : : "global state: %qs -> %qs",
509 : 0 : m_from->get_name (),
510 : 0 : m_to->get_name ());
511 : : }
512 : : }
513 : :
514 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
515 : : state change events: delegate to the pending_diagnostic to
516 : : get any meaning. */
517 : :
518 : : diagnostics::paths::event::meaning
519 : 330 : state_change_event::get_meaning () const
520 : : {
521 : 330 : if (m_pending_diagnostic)
522 : : {
523 : 330 : region_model *model = m_dst_state.m_region_model;
524 : 330 : tree var = model->get_representative_tree (m_sval);
525 : 330 : tree origin = model->get_representative_tree (m_origin);
526 : 330 : evdesc::state_change evd (var, origin,
527 : 330 : m_from, m_to, m_emission_id, *this);
528 : 330 : return m_pending_diagnostic->get_meaning_for_state_change (evd);
529 : : }
530 : : else
531 : 0 : return meaning ();
532 : : }
533 : :
534 : : /* class superedge_event : public checker_event. */
535 : :
536 : : /* Implementation of diagnostics::paths::event::maybe_add_sarif_properties
537 : : for superedge_event. */
538 : :
539 : : void
540 : 26 : superedge_event::
541 : : maybe_add_sarif_properties (diagnostics::sarif_builder &builder,
542 : : diagnostics::sarif_object &thread_flow_loc_obj)
543 : : const
544 : : {
545 : 26 : checker_event::maybe_add_sarif_properties (builder, thread_flow_loc_obj);
546 : 26 : auto &props = thread_flow_loc_obj.get_or_create_properties ();
547 : : #define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
548 : 26 : if (m_sedge)
549 : 26 : props.set (PROPERTY_PREFIX "superedge", m_sedge->to_json ());
550 : : #undef PROPERTY_PREFIX
551 : 26 : }
552 : :
553 : : /* Get the callgraph_superedge for this superedge_event, which must be
554 : : for an interprocedural edge, rather than a CFG edge. */
555 : :
556 : : const callgraph_superedge&
557 : 1644 : superedge_event::get_callgraph_superedge () const
558 : : {
559 : 1644 : gcc_assert (m_sedge->m_kind != SUPEREDGE_CFG_EDGE);
560 : 1644 : return *m_sedge->dyn_cast_callgraph_superedge ();
561 : : }
562 : :
563 : : /* Determine if this event should be filtered at the given verbosity
564 : : level. */
565 : :
566 : : bool
567 : 11075 : superedge_event::should_filter_p (int verbosity) const
568 : : {
569 : 11075 : switch (m_sedge->m_kind)
570 : : {
571 : 11075 : case SUPEREDGE_CFG_EDGE:
572 : 11075 : {
573 : 11075 : if (verbosity < 2)
574 : : return true;
575 : :
576 : 10878 : if (verbosity < 4)
577 : : {
578 : : /* Filter events with empty descriptions. This ought to filter
579 : : FALLTHRU, but retain true/false/switch edges. */
580 : 10878 : auto pp = global_dc->clone_printer ();
581 : 10878 : print_desc (*pp.get ());
582 : 10878 : if (pp_formatted_text (pp.get ()) [0] == '\0')
583 : 8154 : return true;
584 : 10878 : }
585 : : }
586 : : break;
587 : :
588 : : default:
589 : : break;
590 : : }
591 : : return false;
592 : : }
593 : :
594 : : const program_state *
595 : 15 : superedge_event::get_program_state () const
596 : : {
597 : 15 : return &m_eedge.m_dest->get_state ();
598 : : }
599 : :
600 : : /* superedge_event's ctor. */
601 : :
602 : 24336 : superedge_event::superedge_event (enum event_kind kind,
603 : : const exploded_edge &eedge,
604 : 24336 : const event_loc_info &loc_info)
605 : : : checker_event (kind, loc_info),
606 : 24336 : m_eedge (eedge), m_sedge (eedge.m_sedge),
607 : 24336 : m_var (NULL_TREE), m_critical_state (0)
608 : : {
609 : : /* Note that m_sedge can be nullptr for e.g. jumps through
610 : : function pointers. */
611 : 24336 : }
612 : :
613 : : /* class cfg_edge_event : public superedge_event. */
614 : :
615 : : /* Get the cfg_superedge for this cfg_edge_event. */
616 : :
617 : : const cfg_superedge &
618 : 8452 : cfg_edge_event::get_cfg_superedge () const
619 : : {
620 : 8452 : return *m_sedge->dyn_cast_cfg_superedge ();
621 : : }
622 : :
623 : : /* cfg_edge_event's ctor. */
624 : :
625 : 22459 : cfg_edge_event::cfg_edge_event (enum event_kind kind,
626 : : const exploded_edge &eedge,
627 : 22459 : const event_loc_info &loc_info)
628 : 22459 : : superedge_event (kind, eedge, loc_info)
629 : : {
630 : 22459 : gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
631 : 22459 : }
632 : :
633 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
634 : : CFG edge events. */
635 : :
636 : : diagnostics::paths::event::meaning
637 : 282 : cfg_edge_event::get_meaning () const
638 : : {
639 : 282 : const cfg_superedge& cfg_sedge = get_cfg_superedge ();
640 : 282 : if (cfg_sedge.true_value_p ())
641 : 116 : return meaning (verb::branch, property::true_);
642 : 166 : else if (cfg_sedge.false_value_p ())
643 : 126 : return meaning (verb::branch, property::false_);
644 : : else
645 : 40 : return meaning ();
646 : : }
647 : :
648 : : /* class start_cfg_edge_event : public cfg_edge_event. */
649 : :
650 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
651 : : start_cfg_edge_event.
652 : :
653 : : If -fanalyzer-verbose-edges, then generate low-level descriptions, such
654 : : as
655 : : "taking 'true' edge SN:7 -> SN:8".
656 : :
657 : : Otherwise, generate strings using the label of the underlying CFG if
658 : : any, such as:
659 : : "following 'true' branch..." or
660 : : "following 'case 3' branch..."
661 : : "following 'default' branch..."
662 : :
663 : : For conditionals, attempt to supply a description of the condition that
664 : : holds, such as:
665 : : "following 'false' branch (when 'ptr' is non-NULL)..."
666 : :
667 : : Failing that, print nothing (which will lead to this event
668 : : being filtered). */
669 : :
670 : : void
671 : 15774 : start_cfg_edge_event::print_desc (pretty_printer &pp) const
672 : : {
673 : 15774 : bool user_facing = !flag_analyzer_verbose_edges;
674 : 15774 : label_text edge_desc (m_sedge->get_description (user_facing));
675 : 15774 : if (user_facing)
676 : : {
677 : 15774 : if (edge_desc.get () && strlen (edge_desc.get ()) > 0)
678 : : {
679 : 7620 : label_text cond_desc = maybe_describe_condition (pp_show_color (&pp));
680 : 7620 : label_text result;
681 : 7620 : if (cond_desc.get ())
682 : 4013 : pp_printf (&pp,
683 : : "following %qs branch (%s)...",
684 : : edge_desc.get (), cond_desc.get ());
685 : : else
686 : 3607 : pp_printf (&pp,
687 : : "following %qs branch...",
688 : : edge_desc.get ());
689 : 11573 : }
690 : : }
691 : : else
692 : : {
693 : 0 : if (strlen (edge_desc.get ()) > 0)
694 : 0 : return pp_printf (&pp,
695 : : "taking %qs edge SN:%i -> SN:%i",
696 : : edge_desc.get (),
697 : 0 : m_sedge->m_src->m_index,
698 : 0 : m_sedge->m_dest->m_index);
699 : : else
700 : 0 : return pp_printf (&pp,
701 : : "taking edge SN:%i -> SN:%i",
702 : 0 : m_sedge->m_src->m_index,
703 : 0 : m_sedge->m_dest->m_index);
704 : : }
705 : 15774 : }
706 : :
707 : : /* Attempt to generate a description of any condition that holds at this edge.
708 : :
709 : : The intent is to make the user-facing messages more clear, especially for
710 : : cases where there's a single or double-negative, such as
711 : : when describing the false branch of an inverted condition.
712 : :
713 : : For example, rather than printing just:
714 : :
715 : : | if (!ptr)
716 : : | ~
717 : : | |
718 : : | (1) following 'false' branch...
719 : :
720 : : it's clearer to spell out the condition that holds:
721 : :
722 : : | if (!ptr)
723 : : | ~
724 : : | |
725 : : | (1) following 'false' branch (when 'ptr' is non-NULL)...
726 : : ^^^^^^^^^^^^^^^^^^^^^^
727 : :
728 : : In the above example, this function would generate the highlighted
729 : : string: "when 'ptr' is non-NULL".
730 : :
731 : : If the edge is not a condition, or it's not clear that a description of
732 : : the condition would be helpful to the user, return NULL. */
733 : :
734 : : label_text
735 : 7730 : start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const
736 : : {
737 : 7730 : const cfg_superedge& cfg_sedge = get_cfg_superedge ();
738 : :
739 : 7730 : if (cfg_sedge.true_value_p () || cfg_sedge.false_value_p ())
740 : : {
741 : 7319 : const gimple *last_stmt = m_sedge->m_src->get_last_stmt ();
742 : 7319 : if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
743 : : {
744 : 7319 : enum tree_code op = gimple_cond_code (cond_stmt);
745 : 7319 : tree lhs = gimple_cond_lhs (cond_stmt);
746 : 7319 : tree rhs = gimple_cond_rhs (cond_stmt);
747 : 7319 : if (cfg_sedge.false_value_p ())
748 : 3378 : op = invert_tree_comparison (op, false /* honor_nans */);
749 : 7319 : return maybe_describe_condition (can_colorize,
750 : 7319 : lhs, op, rhs);
751 : : }
752 : : }
753 : 411 : return label_text::borrow (nullptr);
754 : : }
755 : :
756 : : /* Subroutine of maybe_describe_condition above.
757 : :
758 : : Attempt to generate a user-facing description of the condition
759 : : LHS OP RHS, but only if it is likely to make it easier for the
760 : : user to understand a condition. */
761 : :
762 : : label_text
763 : 7319 : start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
764 : : tree lhs,
765 : : enum tree_code op,
766 : : tree rhs)
767 : : {
768 : : /* In theory we could just build a tree via
769 : : fold_build2 (op, boolean_type_node, lhs, rhs)
770 : : and print it with %qE on it, but this leads to warts such as
771 : : parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
772 : :
773 : : /* Special-case: describe testing the result of strcmp, as figuring
774 : : out what the "true" or "false" path is can be confusing to the user. */
775 : 7319 : if (TREE_CODE (lhs) == SSA_NAME
776 : 7319 : && zerop (rhs))
777 : : {
778 : 5688 : if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
779 : 2320 : if (is_special_named_call_p (*call, "strcmp", 2))
780 : : {
781 : 60 : if (op == EQ_EXPR)
782 : 9 : return label_text::borrow ("when the strings are equal");
783 : 51 : if (op == NE_EXPR)
784 : 51 : return label_text::borrow ("when the strings are non-equal");
785 : : }
786 : : }
787 : :
788 : : /* Only attempt to generate text for sufficiently simple expressions. */
789 : 7259 : if (!should_print_expr_p (lhs))
790 : 3156 : return label_text::borrow (nullptr);
791 : 4103 : if (!should_print_expr_p (rhs))
792 : 58 : return label_text::borrow (nullptr);
793 : :
794 : : /* Special cases for pointer comparisons against NULL. */
795 : 6551 : if (POINTER_TYPE_P (TREE_TYPE (lhs))
796 : 1539 : && POINTER_TYPE_P (TREE_TYPE (rhs))
797 : 5584 : && zerop (rhs))
798 : : {
799 : 1470 : if (op == EQ_EXPR)
800 : 393 : return make_label_text (can_colorize, "when %qE is NULL",
801 : 393 : lhs);
802 : 1077 : if (op == NE_EXPR)
803 : 1077 : return make_label_text (can_colorize, "when %qE is non-NULL",
804 : 1077 : lhs);
805 : : }
806 : :
807 : 2575 : return make_label_text (can_colorize, "when %<%E %s %E%>",
808 : 2575 : lhs, op_symbol_code (op), rhs);
809 : : }
810 : :
811 : : /* Subroutine of maybe_describe_condition.
812 : :
813 : : Return true if EXPR is we will get suitable user-facing output
814 : : from %E on it. */
815 : :
816 : : bool
817 : 11362 : start_cfg_edge_event::should_print_expr_p (tree expr)
818 : : {
819 : 15797 : if (TREE_CODE (expr) == SSA_NAME)
820 : : {
821 : 7649 : if (SSA_NAME_VAR (expr))
822 : : return should_print_expr_p (SSA_NAME_VAR (expr));
823 : : else
824 : : return false;
825 : : }
826 : :
827 : 8148 : if (DECL_P (expr))
828 : : return true;
829 : :
830 : 3713 : if (CONSTANT_CLASS_P (expr))
831 : 3713 : return true;
832 : :
833 : : return false;
834 : : }
835 : :
836 : : /* class call_event : public superedge_event. */
837 : :
838 : : /* call_event's ctor. */
839 : :
840 : 1220 : call_event::call_event (const exploded_edge &eedge,
841 : 1220 : const event_loc_info &loc_info)
842 : 1220 : : superedge_event (event_kind::call_edge, eedge, loc_info)
843 : : {
844 : 1220 : if (eedge.m_sedge)
845 : 1187 : gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
846 : :
847 : 1220 : m_src_snode = eedge.m_src->get_supernode ();
848 : 1220 : m_dest_snode = eedge.m_dest->get_supernode ();
849 : 1220 : }
850 : :
851 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
852 : : call_event.
853 : :
854 : : If this call event passes critical state for an sm-based warning,
855 : : allow the diagnostic to generate a precise description, such as:
856 : :
857 : : "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
858 : :
859 : : Otherwise, generate a description of the form
860 : : "calling 'foo' from 'bar'". */
861 : :
862 : : void
863 : 1748 : call_event::print_desc (pretty_printer &pp) const
864 : : {
865 : 1748 : if (m_critical_state && m_pending_diagnostic)
866 : : {
867 : 351 : gcc_assert (m_var);
868 : 351 : tree var = fixup_tree_for_diagnostic (m_var);
869 : 351 : evdesc::call_with_state evd (m_src_snode->m_fun->decl,
870 : 351 : m_dest_snode->m_fun->decl,
871 : : var,
872 : 351 : m_critical_state);
873 : 351 : if (m_pending_diagnostic->describe_call_with_state (pp, evd))
874 : 150 : return;
875 : : }
876 : :
877 : 1598 : pp_printf (&pp,
878 : : "calling %qE from %qE",
879 : : get_callee_fndecl (),
880 : : get_caller_fndecl ());
881 : : }
882 : :
883 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
884 : : function call events. */
885 : :
886 : : diagnostics::paths::event::meaning
887 : 126 : call_event::get_meaning () const
888 : : {
889 : 126 : return meaning (verb::call, noun::function);
890 : : }
891 : :
892 : : /* Override of checker_event::is_call_p for calls. */
893 : :
894 : : bool
895 : 2061 : call_event::is_call_p () const
896 : : {
897 : 2061 : return true;
898 : : }
899 : :
900 : : tree
901 : 1666 : call_event::get_caller_fndecl () const
902 : : {
903 : 1666 : return m_src_snode->m_fun->decl;
904 : : }
905 : :
906 : : tree
907 : 1666 : call_event::get_callee_fndecl () const
908 : : {
909 : 1666 : return m_dest_snode->m_fun->decl;
910 : : }
911 : :
912 : : const program_state *
913 : 3 : call_event::get_program_state () const
914 : : {
915 : : /* Use the state at the source (at the caller),
916 : : rather than the one at the dest, which has a frame for the callee. */
917 : 3 : return &m_eedge.m_src->get_state ();
918 : : }
919 : :
920 : : /* class return_event : public superedge_event. */
921 : :
922 : : /* return_event's ctor. */
923 : :
924 : 657 : return_event::return_event (const exploded_edge &eedge,
925 : 657 : const event_loc_info &loc_info)
926 : 657 : : superedge_event (event_kind::return_edge, eedge, loc_info)
927 : : {
928 : 657 : if (eedge.m_sedge)
929 : 639 : gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
930 : :
931 : 657 : m_src_snode = eedge.m_src->get_supernode ();
932 : 657 : m_dest_snode = eedge.m_dest->get_supernode ();
933 : 657 : }
934 : :
935 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
936 : : return_event.
937 : :
938 : : If this return event returns critical state for an sm-based warning,
939 : : allow the diagnostic to generate a precise description, such as:
940 : :
941 : : "possible of NULL to 'foo' from 'bar'"
942 : :
943 : : Otherwise, generate a description of the form
944 : : "returning to 'foo' from 'bar'. */
945 : :
946 : : void
947 : 698 : return_event::print_desc (pretty_printer &pp) const
948 : : {
949 : : /* For greatest precision-of-wording, if this is returning the
950 : : state involved in the pending diagnostic, give the pending
951 : : diagnostic a chance to describe this return (in terms of
952 : : itself). */
953 : 698 : if (m_critical_state && m_pending_diagnostic)
954 : : {
955 : 104 : evdesc::return_of_state evd (m_dest_snode->m_fun->decl,
956 : 104 : m_src_snode->m_fun->decl,
957 : 104 : m_critical_state);
958 : 104 : if (m_pending_diagnostic->describe_return_of_state (pp, evd))
959 : 44 : return;
960 : : }
961 : 654 : pp_printf (&pp,
962 : : "returning to %qE from %qE",
963 : 654 : m_dest_snode->m_fun->decl,
964 : 654 : m_src_snode->m_fun->decl);
965 : : }
966 : :
967 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
968 : : function return events. */
969 : :
970 : : diagnostics::paths::event::meaning
971 : 54 : return_event::get_meaning () const
972 : : {
973 : 54 : return meaning (verb::return_, noun::function);
974 : : }
975 : :
976 : : /* Override of checker_event::is_return_p for returns. */
977 : :
978 : : bool
979 : 657 : return_event::is_return_p () const
980 : : {
981 : 657 : return true;
982 : : }
983 : :
984 : : /* class start_consolidated_cfg_edges_event : public checker_event. */
985 : :
986 : : void
987 : 165 : start_consolidated_cfg_edges_event::print_desc (pretty_printer &pp) const
988 : : {
989 : 165 : pp_printf (&pp,
990 : : "following %qs branch...",
991 : 165 : m_edge_sense ? "true" : "false");
992 : 165 : }
993 : :
994 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
995 : : start_consolidated_cfg_edges_event. */
996 : :
997 : : diagnostics::paths::event::meaning
998 : 0 : start_consolidated_cfg_edges_event::get_meaning () const
999 : : {
1000 : 0 : return meaning (verb::branch,
1001 : 0 : (m_edge_sense ? property::true_ : property::false_));
1002 : : }
1003 : :
1004 : : /* class inlined_call_event : public checker_event. */
1005 : :
1006 : : void
1007 : 333 : inlined_call_event::print_desc (pretty_printer &pp) const
1008 : : {
1009 : 333 : pp_printf (&pp,
1010 : : "inlined call to %qE from %qE",
1011 : 333 : m_apparent_callee_fndecl,
1012 : 333 : m_apparent_caller_fndecl);
1013 : 333 : }
1014 : :
1015 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
1016 : : reconstructed inlined function calls. */
1017 : :
1018 : : diagnostics::paths::event::meaning
1019 : 72 : inlined_call_event::get_meaning () const
1020 : : {
1021 : 72 : return meaning (verb::call, noun::function);
1022 : : }
1023 : :
1024 : : /* class setjmp_event : public checker_event. */
1025 : :
1026 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
1027 : : setjmp_event. */
1028 : :
1029 : : void
1030 : 40 : setjmp_event::print_desc (pretty_printer &pp) const
1031 : : {
1032 : 40 : pp_printf (&pp,
1033 : : "%qs called here",
1034 : : get_user_facing_name (m_setjmp_call));
1035 : 40 : }
1036 : :
1037 : : /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1038 : :
1039 : : Record this setjmp's event ID into the path, so that rewind events can
1040 : : use it. */
1041 : :
1042 : : void
1043 : 20 : setjmp_event::prepare_for_emission (checker_path *path,
1044 : : pending_diagnostic *pd,
1045 : : diagnostics::paths::event_id_t emission_id)
1046 : : {
1047 : 20 : checker_event::prepare_for_emission (path, pd, emission_id);
1048 : 20 : path->record_setjmp_event (m_enode, emission_id);
1049 : 20 : }
1050 : :
1051 : : /* class rewind_event : public checker_event. */
1052 : :
1053 : : /* Get the fndecl containing the site of the longjmp call. */
1054 : :
1055 : : tree
1056 : 90 : rewind_event::get_longjmp_caller () const
1057 : : {
1058 : 90 : return m_eedge->m_src->get_function ()->decl;
1059 : : }
1060 : :
1061 : : /* Get the fndecl containing the site of the setjmp call. */
1062 : :
1063 : : tree
1064 : 82 : rewind_event::get_setjmp_caller () const
1065 : : {
1066 : 82 : return m_eedge->m_dest->get_function ()->decl;
1067 : : }
1068 : :
1069 : : /* rewind_event's ctor. */
1070 : :
1071 : 30 : rewind_event::rewind_event (const exploded_edge *eedge,
1072 : : enum event_kind kind,
1073 : : const event_loc_info &loc_info,
1074 : 30 : const rewind_info_t *rewind_info)
1075 : : : checker_event (kind, loc_info),
1076 : 30 : m_rewind_info (rewind_info),
1077 : 30 : m_eedge (eedge)
1078 : : {
1079 : 30 : gcc_assert (m_eedge->m_custom_info.get () == m_rewind_info);
1080 : 30 : }
1081 : :
1082 : : /* class rewind_from_longjmp_event : public rewind_event. */
1083 : :
1084 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
1085 : : rewind_from_longjmp_event. */
1086 : :
1087 : : void
1088 : 30 : rewind_from_longjmp_event::print_desc (pretty_printer &pp) const
1089 : : {
1090 : 30 : const char *src_name
1091 : 30 : = get_user_facing_name (m_rewind_info->get_longjmp_call ());
1092 : :
1093 : 30 : if (get_longjmp_caller () == get_setjmp_caller ())
1094 : : /* Special-case: purely intraprocedural rewind. */
1095 : 8 : pp_printf (&pp,
1096 : : "rewinding within %qE from %qs...",
1097 : : get_longjmp_caller (),
1098 : : src_name);
1099 : : else
1100 : 22 : pp_printf (&pp,
1101 : : "rewinding from %qs in %qE...",
1102 : : src_name,
1103 : : get_longjmp_caller ());
1104 : 30 : }
1105 : :
1106 : : /* class rewind_to_setjmp_event : public rewind_event. */
1107 : :
1108 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
1109 : : rewind_to_setjmp_event. */
1110 : :
1111 : : void
1112 : 30 : rewind_to_setjmp_event::print_desc (pretty_printer &pp) const
1113 : : {
1114 : 30 : const char *dst_name
1115 : 30 : = get_user_facing_name (m_rewind_info->get_setjmp_call ());
1116 : :
1117 : : /* If we can, identify the ID of the setjmp_event. */
1118 : 30 : if (m_original_setjmp_event_id.known_p ())
1119 : : {
1120 : 15 : if (get_longjmp_caller () == get_setjmp_caller ())
1121 : : /* Special-case: purely intraprocedural rewind. */
1122 : 4 : pp_printf (&pp,
1123 : : "...to %qs (saved at %@)",
1124 : : dst_name,
1125 : : &m_original_setjmp_event_id);
1126 : : else
1127 : 11 : pp_printf (&pp,
1128 : : "...to %qs in %qE (saved at %@)",
1129 : : dst_name,
1130 : : get_setjmp_caller (),
1131 : : &m_original_setjmp_event_id);
1132 : : }
1133 : : else
1134 : : {
1135 : 15 : if (get_longjmp_caller () == get_setjmp_caller ())
1136 : : /* Special-case: purely intraprocedural rewind. */
1137 : 4 : pp_printf (&pp,
1138 : : "...to %qs",
1139 : : dst_name);
1140 : : else
1141 : 11 : pp_printf (&pp,
1142 : : "...to %qs in %qE",
1143 : : dst_name,
1144 : : get_setjmp_caller ());
1145 : : }
1146 : 30 : }
1147 : :
1148 : : /* Implementation of checker_event::prepare_for_emission vfunc for
1149 : : rewind_to_setjmp_event.
1150 : :
1151 : : Attempt to look up the setjmp event ID that recorded the jmp_buf
1152 : : for this rewind. */
1153 : :
1154 : : void
1155 : 15 : rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
1156 : : pending_diagnostic *pd,
1157 : : diagnostics::paths::event_id_t emission_id)
1158 : : {
1159 : 15 : checker_event::prepare_for_emission (path, pd, emission_id);
1160 : 15 : path->get_setjmp_event (m_rewind_info->get_enode_origin (),
1161 : : &m_original_setjmp_event_id);
1162 : 15 : }
1163 : :
1164 : : /* class throw_event : public checker_event. */
1165 : :
1166 : : /* class explicit_throw_event : public throw_event. */
1167 : : void
1168 : 126 : explicit_throw_event::print_desc (pretty_printer &pp) const
1169 : : {
1170 : 126 : if (m_is_rethrow)
1171 : : {
1172 : 18 : if (m_type)
1173 : 18 : pp_printf (&pp, "rethrowing exception of type %qT here...", m_type);
1174 : : else
1175 : 0 : pp_printf (&pp, "rethrowing exception here...");
1176 : : }
1177 : : else
1178 : : {
1179 : 108 : if (m_type)
1180 : 108 : pp_printf (&pp, "throwing exception of type %qT here...", m_type);
1181 : : else
1182 : 0 : pp_printf (&pp, "throwing exception here...");
1183 : : }
1184 : 126 : }
1185 : :
1186 : : /* class throw_from_call_to_external_fn_event : public throw_event. */
1187 : :
1188 : : void
1189 : 44 : throw_from_call_to_external_fn_event::print_desc (pretty_printer &pp) const
1190 : : {
1191 : 44 : if (m_fndecl)
1192 : 44 : pp_printf (&pp, "if %qD throws an exception...", m_fndecl);
1193 : : else
1194 : 0 : pp_printf (&pp, "if the called function throws an exception...");
1195 : 44 : }
1196 : :
1197 : : // class unwind_event : public checker_event
1198 : :
1199 : : void
1200 : 20 : unwind_event::print_desc (pretty_printer &pp) const
1201 : : {
1202 : 20 : if (m_num_frames > 1)
1203 : 12 : pp_printf (&pp, "unwinding %i stack frames", m_num_frames);
1204 : : else
1205 : 8 : pp_printf (&pp, "unwinding stack frame");
1206 : 20 : }
1207 : :
1208 : : /* class warning_event : public checker_event. */
1209 : :
1210 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
1211 : : warning_event.
1212 : :
1213 : : If the pending diagnostic implements describe_final_event, use it,
1214 : : generating a precise description e.g.
1215 : : "second 'free' here; first 'free' was at (7)"
1216 : :
1217 : : Otherwise generate a generic description. */
1218 : :
1219 : : void
1220 : 7878 : warning_event::print_desc (pretty_printer &pp) const
1221 : : {
1222 : 7878 : if (m_pending_diagnostic)
1223 : : {
1224 : 7878 : tree var = fixup_tree_for_diagnostic (m_var);
1225 : 7878 : evdesc::final_event evd (var, m_state, *this);
1226 : 7878 : if (m_pending_diagnostic->describe_final_event (pp, evd))
1227 : : {
1228 : 7302 : if (m_sm && flag_analyzer_verbose_state_changes)
1229 : : {
1230 : 72 : if (var)
1231 : 64 : pp_printf (&pp, " (%qE is in state %qs)",
1232 : 64 : var, m_state->get_name ());
1233 : : else
1234 : 8 : pp_printf (&pp, " (in global state %qs)",
1235 : 8 : m_state->get_name ());
1236 : : }
1237 : 7302 : return;
1238 : : }
1239 : : }
1240 : :
1241 : 576 : if (m_sm)
1242 : : {
1243 : 64 : if (m_var)
1244 : 64 : pp_printf (&pp, "here (%qE is in state %qs)",
1245 : 64 : m_var, m_state->get_name ());
1246 : : else
1247 : 0 : pp_printf (&pp, "here (in global state %qs)",
1248 : 0 : m_state->get_name ());
1249 : 64 : return;
1250 : : }
1251 : : else
1252 : 512 : pp_string (&pp, "here");
1253 : : }
1254 : :
1255 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
1256 : : warning_event. */
1257 : :
1258 : : diagnostics::paths::event::meaning
1259 : 219 : warning_event::get_meaning () const
1260 : : {
1261 : 219 : return meaning (verb::danger, noun::unknown);
1262 : : }
1263 : :
1264 : : const program_state *
1265 : 3 : warning_event::get_program_state () const
1266 : : {
1267 : 3 : if (m_program_state)
1268 : : return m_program_state.get ();
1269 : : else
1270 : 1 : return &m_enode->get_state ();
1271 : : }
1272 : :
1273 : : } // namespace ana
1274 : :
1275 : : #endif /* #if ENABLE_ANALYZER */
|