Daily bump.
[official-gcc.git] / gcc / analyzer / checker-event.cc
blob593f364e1d665a34eb9ab7cc6bfbbc21a3286e4c
1 /* Subclasses of diagnostic_event for analyzer diagnostics.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
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.
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.
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/>. */
21 #include "config.h"
22 #define INCLUDE_MEMORY
23 #define INCLUDE_VECTOR
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tree.h"
27 #include "function.h"
28 #include "basic-block.h"
29 #include "gimple.h"
30 #include "diagnostic-core.h"
31 #include "gimple-pretty-print.h"
32 #include "fold-const.h"
33 #include "diagnostic-path.h"
34 #include "options.h"
35 #include "cgraph.h"
36 #include "cfg.h"
37 #include "digraph.h"
38 #include "diagnostic-event-id.h"
39 #include "analyzer/analyzer.h"
40 #include "analyzer/analyzer-logging.h"
41 #include "analyzer/sm.h"
42 #include "sbitmap.h"
43 #include "bitmap.h"
44 #include "ordered-hash-map.h"
45 #include "analyzer/call-string.h"
46 #include "analyzer/program-point.h"
47 #include "analyzer/store.h"
48 #include "analyzer/region-model.h"
49 #include "analyzer/program-state.h"
50 #include "analyzer/checker-path.h"
51 #include "gimple-iterator.h"
52 #include "inlining-iterator.h"
53 #include "analyzer/supergraph.h"
54 #include "analyzer/pending-diagnostic.h"
55 #include "analyzer/diagnostic-manager.h"
56 #include "analyzer/constraint-manager.h"
57 #include "analyzer/checker-event.h"
58 #include "analyzer/exploded-graph.h"
59 #include "diagnostic-format-sarif.h"
60 #include "tree-logical-location.h"
62 #if ENABLE_ANALYZER
64 namespace ana {
66 /* Get a string for EK. */
68 const char *
69 event_kind_to_string (enum event_kind ek)
71 switch (ek)
73 default:
74 gcc_unreachable ();
75 case EK_DEBUG:
76 return "EK_DEBUG";
77 case EK_CUSTOM:
78 return "EK_CUSTOM";
79 case EK_STMT:
80 return "EK_STMT";
81 case EK_REGION_CREATION:
82 return "EK_REGION_CREATION";
83 case EK_FUNCTION_ENTRY:
84 return "EK_FUNCTION_ENTRY";
85 case EK_STATE_CHANGE:
86 return "EK_STATE_CHANGE";
87 case EK_START_CFG_EDGE:
88 return "EK_START_CFG_EDGE";
89 case EK_END_CFG_EDGE:
90 return "EK_END_CFG_EDGE";
91 case EK_CALL_EDGE:
92 return "EK_CALL_EDGE";
93 case EK_RETURN_EDGE:
94 return "EK_RETURN_EDGE";
95 case EK_START_CONSOLIDATED_CFG_EDGES:
96 return "EK_START_CONSOLIDATED_CFG_EDGES";
97 case EK_END_CONSOLIDATED_CFG_EDGES:
98 return "EK_END_CONSOLIDATED_CFG_EDGES";
99 case EK_INLINED_CALL:
100 return "EK_INLINED_CALL";
101 case EK_SETJMP:
102 return "EK_SETJMP";
103 case EK_REWIND_FROM_LONGJMP:
104 return "EK_REWIND_FROM_LONGJMP";
105 case EK_REWIND_TO_SETJMP:
106 return "EK_REWIND_TO_SETJMP";
107 case EK_WARNING:
108 return "EK_WARNING";
112 /* class checker_event : public diagnostic_event. */
114 /* checker_event's ctor. */
116 checker_event::checker_event (enum event_kind kind,
117 const event_loc_info &loc_info)
118 : m_kind (kind), m_loc (loc_info.m_loc),
119 m_original_fndecl (loc_info.m_fndecl),
120 m_effective_fndecl (loc_info.m_fndecl),
121 m_original_depth (loc_info.m_depth),
122 m_effective_depth (loc_info.m_depth),
123 m_pending_diagnostic (NULL), m_emission_id (),
124 m_logical_loc (loc_info.m_fndecl)
126 /* Update effective fndecl and depth if inlining has been recorded. */
127 if (flag_analyzer_undo_inlining)
129 inlining_info info (m_loc);
130 if (info.get_inner_fndecl ())
132 m_effective_fndecl = info.get_inner_fndecl ();
133 m_effective_depth += info.get_extra_frames ();
134 m_logical_loc = tree_logical_location (m_effective_fndecl);
139 /* No-op implementation of diagnostic_event::get_meaning vfunc for
140 checker_event: checker events have no meaning by default. */
142 diagnostic_event::meaning
143 checker_event::get_meaning () const
145 return meaning ();
148 /* Implementation of diagnostic_event::maybe_add_sarif_properties
149 for checker_event. */
151 void
152 checker_event::
153 maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj) const
155 sarif_property_bag &props = thread_flow_loc_obj.get_or_create_properties ();
156 #define PROPERTY_PREFIX "gcc/analyzer/checker_event/"
157 props.set (PROPERTY_PREFIX "emission_id",
158 diagnostic_event_id_to_json (m_emission_id));
159 props.set_string (PROPERTY_PREFIX "kind", event_kind_to_string (m_kind));
161 if (m_original_fndecl != m_effective_fndecl)
163 tree_logical_location logical_loc (m_original_fndecl);
164 props.set (PROPERTY_PREFIX "original_fndecl",
165 make_sarif_logical_location_object (logical_loc));
167 if (m_original_depth != m_effective_depth)
168 props.set_integer (PROPERTY_PREFIX "original_depth", m_original_depth);
169 #undef PROPERTY_PREFIX
172 /* Dump this event to PP (for debugging/logging purposes). */
174 void
175 checker_event::dump (pretty_printer *pp) const
177 label_text event_desc (get_desc (false));
178 pp_printf (pp, "\"%s\" (depth %i",
179 event_desc.get (), m_effective_depth);
181 if (m_effective_depth != m_original_depth)
182 pp_printf (pp, " corrected from %i",
183 m_original_depth);
184 if (m_effective_fndecl)
186 pp_printf (pp, ", fndecl %qE", m_effective_fndecl);
187 if (m_effective_fndecl != m_original_fndecl)
188 pp_printf (pp, " corrected from %qE", m_original_fndecl);
190 pp_printf (pp, ", m_loc=%x)",
191 get_location ());
194 /* Dump this event to stderr (for debugging/logging purposes). */
196 DEBUG_FUNCTION void
197 checker_event::debug () const
199 pretty_printer pp;
200 pp_format_decoder (&pp) = default_tree_printer;
201 pp_show_color (&pp) = pp_show_color (global_dc->printer);
202 pp.set_output_stream (stderr);
203 dump (&pp);
204 pp_newline (&pp);
205 pp_flush (&pp);
208 /* Hook for being notified when this event has its final id EMISSION_ID
209 and is about to emitted for PD.
211 Base implementation of checker_event::prepare_for_emission vfunc;
212 subclasses that override this should chain up to it.
214 Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
215 side-effects of the call to get_desc take place before
216 pending_diagnostic::emit is called.
218 For example, state_change_event::get_desc can call
219 pending_diagnostic::describe_state_change; free_of_non_heap can use this
220 to tweak the message (TODO: would be neater to simply capture the
221 pertinent data within the sm-state). */
223 void
224 checker_event::prepare_for_emission (checker_path *,
225 pending_diagnostic *pd,
226 diagnostic_event_id_t emission_id)
228 m_pending_diagnostic = pd;
229 m_emission_id = emission_id;
231 label_text desc = get_desc (false);
234 /* class debug_event : public checker_event. */
236 /* Implementation of diagnostic_event::get_desc vfunc for
237 debug_event.
238 Use the saved string as the event's description. */
240 label_text
241 debug_event::get_desc (bool) const
243 return label_text::borrow (m_desc);
246 /* class precanned_custom_event : public custom_event. */
248 /* Implementation of diagnostic_event::get_desc vfunc for
249 precanned_custom_event.
250 Use the saved string as the event's description. */
252 label_text
253 precanned_custom_event::get_desc (bool) const
255 return label_text::borrow (m_desc);
258 /* class statement_event : public checker_event. */
260 /* statement_event's ctor. */
262 statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
263 const program_state &dst_state)
264 : checker_event (EK_STMT,
265 event_loc_info (gimple_location (stmt), fndecl, depth)),
266 m_stmt (stmt),
267 m_dst_state (dst_state)
271 /* Implementation of diagnostic_event::get_desc vfunc for
272 statement_event.
273 Use the statement's dump form as the event's description. */
275 label_text
276 statement_event::get_desc (bool) const
278 pretty_printer pp;
279 pp_string (&pp, "stmt: ");
280 pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
281 return label_text::take (xstrdup (pp_formatted_text (&pp)));
284 /* class region_creation_event : public checker_event. */
286 region_creation_event::region_creation_event (const event_loc_info &loc_info)
287 : checker_event (EK_REGION_CREATION, loc_info)
291 /* The various region_creation_event subclasses' get_desc
292 implementations. */
294 label_text
295 region_creation_event_memory_space::get_desc (bool) const
297 switch (m_mem_space)
299 default:
300 return label_text::borrow ("region created here");
301 case MEMSPACE_STACK:
302 return label_text::borrow ("region created on stack here");
303 case MEMSPACE_HEAP:
304 return label_text::borrow ("region created on heap here");
308 label_text
309 region_creation_event_capacity::get_desc (bool can_colorize) const
311 gcc_assert (m_capacity);
312 if (TREE_CODE (m_capacity) == INTEGER_CST)
314 unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
315 return make_label_text_n (can_colorize,
316 hwi,
317 "capacity: %wu byte",
318 "capacity: %wu bytes",
319 hwi);
321 else
322 return make_label_text (can_colorize,
323 "capacity: %qE bytes", m_capacity);
326 label_text
327 region_creation_event_allocation_size::get_desc (bool can_colorize) const
329 if (m_capacity)
331 if (TREE_CODE (m_capacity) == INTEGER_CST)
332 return make_label_text_n (can_colorize,
333 tree_to_uhwi (m_capacity),
334 "allocated %E byte here",
335 "allocated %E bytes here",
336 m_capacity);
337 else
338 return make_label_text (can_colorize,
339 "allocated %qE bytes here",
340 m_capacity);
342 return make_label_text (can_colorize, "allocated here");
345 label_text
346 region_creation_event_debug::get_desc (bool) const
348 pretty_printer pp;
349 pp_format_decoder (&pp) = default_tree_printer;
350 pp_string (&pp, "region creation: ");
351 m_reg->dump_to_pp (&pp, true);
352 if (m_capacity)
353 pp_printf (&pp, " capacity: %qE", m_capacity);
354 return label_text::take (xstrdup (pp_formatted_text (&pp)));
357 /* class function_entry_event : public checker_event. */
359 function_entry_event::function_entry_event (const program_point &dst_point)
360 : checker_event (EK_FUNCTION_ENTRY,
361 event_loc_info (dst_point.get_supernode
362 ()->get_start_location (),
363 dst_point.get_fndecl (),
364 dst_point.get_stack_depth ()))
368 /* Implementation of diagnostic_event::get_desc vfunc for
369 function_entry_event.
371 Use a string such as "entry to 'foo'" as the event's description. */
373 label_text
374 function_entry_event::get_desc (bool can_colorize) const
376 return make_label_text (can_colorize, "entry to %qE", m_effective_fndecl);
379 /* Implementation of diagnostic_event::get_meaning vfunc for
380 function entry. */
382 diagnostic_event::meaning
383 function_entry_event::get_meaning () const
385 return meaning (VERB_enter, NOUN_function);
388 /* class state_change_event : public checker_event. */
390 /* state_change_event's ctor. */
392 state_change_event::state_change_event (const supernode *node,
393 const gimple *stmt,
394 int stack_depth,
395 const state_machine &sm,
396 const svalue *sval,
397 state_machine::state_t from,
398 state_machine::state_t to,
399 const svalue *origin,
400 const program_state &dst_state,
401 const exploded_node *enode)
402 : checker_event (EK_STATE_CHANGE,
403 event_loc_info (stmt->location,
404 node->m_fun->decl,
405 stack_depth)),
406 m_node (node), m_stmt (stmt), m_sm (sm),
407 m_sval (sval), m_from (from), m_to (to),
408 m_origin (origin),
409 m_dst_state (dst_state),
410 m_enode (enode)
414 /* Implementation of diagnostic_event::get_desc vfunc for
415 state_change_event.
417 Attempt to generate a nicer human-readable description.
418 For greatest precision-of-wording, give the pending diagnostic
419 a chance to describe this state change (in terms of the
420 diagnostic).
421 Note that we only have a pending_diagnostic set on the event once
422 the diagnostic is about to being emitted, so the description for
423 an event can change. */
425 label_text
426 state_change_event::get_desc (bool can_colorize) const
428 if (m_pending_diagnostic)
430 region_model *model = m_dst_state.m_region_model;
431 tree var = model->get_representative_tree (m_sval);
432 tree origin = model->get_representative_tree (m_origin);
433 label_text custom_desc
434 = m_pending_diagnostic->describe_state_change
435 (evdesc::state_change (can_colorize, var, origin,
436 m_from, m_to, m_emission_id, *this));
437 if (custom_desc.get ())
439 if (flag_analyzer_verbose_state_changes)
441 /* Get any "meaning" of event. */
442 diagnostic_event::meaning meaning = get_meaning ();
443 pretty_printer meaning_pp;
444 meaning.dump_to_pp (&meaning_pp);
446 /* Append debug version. */
447 if (var)
449 if (m_origin)
450 return make_label_text
451 (can_colorize,
452 "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
453 custom_desc.get (),
454 var,
455 m_from->get_name (),
456 m_to->get_name (),
457 origin,
458 pp_formatted_text (&meaning_pp));
459 else
460 return make_label_text
461 (can_colorize,
462 "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
463 custom_desc.get (),
464 var,
465 m_from->get_name (),
466 m_to->get_name (),
467 pp_formatted_text (&meaning_pp));
469 else
471 if (m_origin)
472 return make_label_text
473 (can_colorize,
474 "%s (state: %qs -> %qs, origin: %qE, meaning: %s)",
475 custom_desc.get (),
476 m_from->get_name (),
477 m_to->get_name (),
478 origin,
479 pp_formatted_text (&meaning_pp));
480 else
481 return make_label_text
482 (can_colorize,
483 "%s (state: %qs -> %qs, NULL origin, meaning: %s)",
484 custom_desc.get (),
485 m_from->get_name (),
486 m_to->get_name (),
487 pp_formatted_text (&meaning_pp));
490 else
491 return custom_desc;
495 /* Fallback description. */
496 if (m_sval)
498 label_text sval_desc = m_sval->get_desc ();
499 if (m_origin)
501 label_text origin_desc = m_origin->get_desc ();
502 return make_label_text
503 (can_colorize,
504 "state of %qs: %qs -> %qs (origin: %qs)",
505 sval_desc.get (),
506 m_from->get_name (),
507 m_to->get_name (),
508 origin_desc.get ());
510 else
511 return make_label_text
512 (can_colorize,
513 "state of %qs: %qs -> %qs (NULL origin)",
514 sval_desc.get (),
515 m_from->get_name (),
516 m_to->get_name ());
518 else
520 gcc_assert (m_origin == NULL);
521 return make_label_text
522 (can_colorize,
523 "global state: %qs -> %qs",
524 m_from->get_name (),
525 m_to->get_name ());
529 /* Implementation of diagnostic_event::get_meaning vfunc for
530 state change events: delegate to the pending_diagnostic to
531 get any meaning. */
533 diagnostic_event::meaning
534 state_change_event::get_meaning () const
536 if (m_pending_diagnostic)
538 region_model *model = m_dst_state.m_region_model;
539 tree var = model->get_representative_tree (m_sval);
540 tree origin = model->get_representative_tree (m_origin);
541 return m_pending_diagnostic->get_meaning_for_state_change
542 (evdesc::state_change (false, var, origin,
543 m_from, m_to, m_emission_id, *this));
545 else
546 return meaning ();
549 /* class superedge_event : public checker_event. */
551 /* Implementation of diagnostic_event::maybe_add_sarif_properties
552 for superedge_event. */
554 void
555 superedge_event::maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj)
556 const
558 checker_event::maybe_add_sarif_properties (thread_flow_loc_obj);
559 sarif_property_bag &props = thread_flow_loc_obj.get_or_create_properties ();
560 #define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
561 if (m_sedge)
562 props.set (PROPERTY_PREFIX "superedge", m_sedge->to_json ());
563 #undef PROPERTY_PREFIX
566 /* Get the callgraph_superedge for this superedge_event, which must be
567 for an interprocedural edge, rather than a CFG edge. */
569 const callgraph_superedge&
570 superedge_event::get_callgraph_superedge () const
572 gcc_assert (m_sedge->m_kind != SUPEREDGE_CFG_EDGE);
573 return *m_sedge->dyn_cast_callgraph_superedge ();
576 /* Determine if this event should be filtered at the given verbosity
577 level. */
579 bool
580 superedge_event::should_filter_p (int verbosity) const
582 switch (m_sedge->m_kind)
584 case SUPEREDGE_CFG_EDGE:
586 if (verbosity < 2)
587 return true;
589 if (verbosity < 4)
591 /* Filter events with empty descriptions. This ought to filter
592 FALLTHRU, but retain true/false/switch edges. */
593 label_text desc = get_desc (false);
594 gcc_assert (desc.get ());
595 if (desc.get ()[0] == '\0')
596 return true;
599 break;
601 default:
602 break;
604 return false;
607 /* superedge_event's ctor. */
609 superedge_event::superedge_event (enum event_kind kind,
610 const exploded_edge &eedge,
611 const event_loc_info &loc_info)
612 : checker_event (kind, loc_info),
613 m_eedge (eedge), m_sedge (eedge.m_sedge),
614 m_var (NULL_TREE), m_critical_state (0)
616 /* Note that m_sedge can be nullptr for e.g. jumps through
617 function pointers. */
620 /* class cfg_edge_event : public superedge_event. */
622 /* Get the cfg_superedge for this cfg_edge_event. */
624 const cfg_superedge &
625 cfg_edge_event::get_cfg_superedge () const
627 return *m_sedge->dyn_cast_cfg_superedge ();
630 /* cfg_edge_event's ctor. */
632 cfg_edge_event::cfg_edge_event (enum event_kind kind,
633 const exploded_edge &eedge,
634 const event_loc_info &loc_info)
635 : superedge_event (kind, eedge, loc_info)
637 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
640 /* Implementation of diagnostic_event::get_meaning vfunc for
641 CFG edge events. */
643 diagnostic_event::meaning
644 cfg_edge_event::get_meaning () const
646 const cfg_superedge& cfg_sedge = get_cfg_superedge ();
647 if (cfg_sedge.true_value_p ())
648 return meaning (VERB_branch, PROPERTY_true);
649 else if (cfg_sedge.false_value_p ())
650 return meaning (VERB_branch, PROPERTY_false);
651 else
652 return meaning ();
655 /* class start_cfg_edge_event : public cfg_edge_event. */
657 /* Implementation of diagnostic_event::get_desc vfunc for
658 start_cfg_edge_event.
660 If -fanalyzer-verbose-edges, then generate low-level descriptions, such
662 "taking 'true' edge SN:7 -> SN:8".
664 Otherwise, generate strings using the label of the underlying CFG if
665 any, such as:
666 "following 'true' branch..." or
667 "following 'case 3' branch..."
668 "following 'default' branch..."
670 For conditionals, attempt to supply a description of the condition that
671 holds, such as:
672 "following 'false' branch (when 'ptr' is non-NULL)..."
674 Failing that, return an empty description (which will lead to this event
675 being filtered). */
677 label_text
678 start_cfg_edge_event::get_desc (bool can_colorize) const
680 bool user_facing = !flag_analyzer_verbose_edges;
681 label_text edge_desc (m_sedge->get_description (user_facing));
682 if (user_facing)
684 if (edge_desc.get () && strlen (edge_desc.get ()) > 0)
686 label_text cond_desc = maybe_describe_condition (can_colorize);
687 label_text result;
688 if (cond_desc.get ())
689 return make_label_text (can_colorize,
690 "following %qs branch (%s)...",
691 edge_desc.get (), cond_desc.get ());
692 else
693 return make_label_text (can_colorize,
694 "following %qs branch...",
695 edge_desc.get ());
697 else
698 return label_text::borrow ("");
700 else
702 if (strlen (edge_desc.get ()) > 0)
703 return make_label_text (can_colorize,
704 "taking %qs edge SN:%i -> SN:%i",
705 edge_desc.get (),
706 m_sedge->m_src->m_index,
707 m_sedge->m_dest->m_index);
708 else
709 return make_label_text (can_colorize,
710 "taking edge SN:%i -> SN:%i",
711 m_sedge->m_src->m_index,
712 m_sedge->m_dest->m_index);
716 /* Attempt to generate a description of any condition that holds at this edge.
718 The intent is to make the user-facing messages more clear, especially for
719 cases where there's a single or double-negative, such as
720 when describing the false branch of an inverted condition.
722 For example, rather than printing just:
724 | if (!ptr)
727 | (1) following 'false' branch...
729 it's clearer to spell out the condition that holds:
731 | if (!ptr)
734 | (1) following 'false' branch (when 'ptr' is non-NULL)...
735 ^^^^^^^^^^^^^^^^^^^^^^
737 In the above example, this function would generate the highlighted
738 string: "when 'ptr' is non-NULL".
740 If the edge is not a condition, or it's not clear that a description of
741 the condition would be helpful to the user, return NULL. */
743 label_text
744 start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const
746 const cfg_superedge& cfg_sedge = get_cfg_superedge ();
748 if (cfg_sedge.true_value_p () || cfg_sedge.false_value_p ())
750 const gimple *last_stmt = m_sedge->m_src->get_last_stmt ();
751 if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
753 enum tree_code op = gimple_cond_code (cond_stmt);
754 tree lhs = gimple_cond_lhs (cond_stmt);
755 tree rhs = gimple_cond_rhs (cond_stmt);
756 if (cfg_sedge.false_value_p ())
757 op = invert_tree_comparison (op, false /* honor_nans */);
758 return maybe_describe_condition (can_colorize,
759 lhs, op, rhs);
762 return label_text::borrow (NULL);
765 /* Subroutine of maybe_describe_condition above.
767 Attempt to generate a user-facing description of the condition
768 LHS OP RHS, but only if it is likely to make it easier for the
769 user to understand a condition. */
771 label_text
772 start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
773 tree lhs,
774 enum tree_code op,
775 tree rhs)
777 /* In theory we could just build a tree via
778 fold_build2 (op, boolean_type_node, lhs, rhs)
779 and print it with %qE on it, but this leads to warts such as
780 parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
782 /* Special-case: describe testing the result of strcmp, as figuring
783 out what the "true" or "false" path is can be confusing to the user. */
784 if (TREE_CODE (lhs) == SSA_NAME
785 && zerop (rhs))
787 if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
788 if (is_special_named_call_p (call, "strcmp", 2))
790 if (op == EQ_EXPR)
791 return label_text::borrow ("when the strings are equal");
792 if (op == NE_EXPR)
793 return label_text::borrow ("when the strings are non-equal");
797 /* Only attempt to generate text for sufficiently simple expressions. */
798 if (!should_print_expr_p (lhs))
799 return label_text::borrow (NULL);
800 if (!should_print_expr_p (rhs))
801 return label_text::borrow (NULL);
803 /* Special cases for pointer comparisons against NULL. */
804 if (POINTER_TYPE_P (TREE_TYPE (lhs))
805 && POINTER_TYPE_P (TREE_TYPE (rhs))
806 && zerop (rhs))
808 if (op == EQ_EXPR)
809 return make_label_text (can_colorize, "when %qE is NULL",
810 lhs);
811 if (op == NE_EXPR)
812 return make_label_text (can_colorize, "when %qE is non-NULL",
813 lhs);
816 return make_label_text (can_colorize, "when %<%E %s %E%>",
817 lhs, op_symbol_code (op), rhs);
820 /* Subroutine of maybe_describe_condition.
822 Return true if EXPR is we will get suitable user-facing output
823 from %E on it. */
825 bool
826 start_cfg_edge_event::should_print_expr_p (tree expr)
828 if (TREE_CODE (expr) == SSA_NAME)
830 if (SSA_NAME_VAR (expr))
831 return should_print_expr_p (SSA_NAME_VAR (expr));
832 else
833 return false;
836 if (DECL_P (expr))
837 return true;
839 if (CONSTANT_CLASS_P (expr))
840 return true;
842 return false;
845 /* class call_event : public superedge_event. */
847 /* call_event's ctor. */
849 call_event::call_event (const exploded_edge &eedge,
850 const event_loc_info &loc_info)
851 : superedge_event (EK_CALL_EDGE, eedge, loc_info)
853 if (eedge.m_sedge)
854 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
856 m_src_snode = eedge.m_src->get_supernode ();
857 m_dest_snode = eedge.m_dest->get_supernode ();
860 /* Implementation of diagnostic_event::get_desc vfunc for
861 call_event.
863 If this call event passes critical state for an sm-based warning,
864 allow the diagnostic to generate a precise description, such as:
866 "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
868 Otherwise, generate a description of the form
869 "calling 'foo' from 'bar'". */
871 label_text
872 call_event::get_desc (bool can_colorize) const
874 if (m_critical_state && m_pending_diagnostic)
876 gcc_assert (m_var);
877 tree var = fixup_tree_for_diagnostic (m_var);
878 label_text custom_desc
879 = m_pending_diagnostic->describe_call_with_state
880 (evdesc::call_with_state (can_colorize,
881 m_src_snode->m_fun->decl,
882 m_dest_snode->m_fun->decl,
883 var,
884 m_critical_state));
885 if (custom_desc.get ())
886 return custom_desc;
889 return make_label_text (can_colorize,
890 "calling %qE from %qE",
891 get_callee_fndecl (),
892 get_caller_fndecl ());
895 /* Implementation of diagnostic_event::get_meaning vfunc for
896 function call events. */
898 diagnostic_event::meaning
899 call_event::get_meaning () const
901 return meaning (VERB_call, NOUN_function);
904 /* Override of checker_event::is_call_p for calls. */
906 bool
907 call_event::is_call_p () const
909 return true;
912 tree
913 call_event::get_caller_fndecl () const
915 return m_src_snode->m_fun->decl;
918 tree
919 call_event::get_callee_fndecl () const
921 return m_dest_snode->m_fun->decl;
924 /* class return_event : public superedge_event. */
926 /* return_event's ctor. */
928 return_event::return_event (const exploded_edge &eedge,
929 const event_loc_info &loc_info)
930 : superedge_event (EK_RETURN_EDGE, eedge, loc_info)
932 if (eedge.m_sedge)
933 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
935 m_src_snode = eedge.m_src->get_supernode ();
936 m_dest_snode = eedge.m_dest->get_supernode ();
939 /* Implementation of diagnostic_event::get_desc vfunc for
940 return_event.
942 If this return event returns critical state for an sm-based warning,
943 allow the diagnostic to generate a precise description, such as:
945 "possible of NULL to 'foo' from 'bar'"
947 Otherwise, generate a description of the form
948 "returning to 'foo' from 'bar'. */
950 label_text
951 return_event::get_desc (bool can_colorize) const
953 /* For greatest precision-of-wording, if this is returning the
954 state involved in the pending diagnostic, give the pending
955 diagnostic a chance to describe this return (in terms of
956 itself). */
957 if (m_critical_state && m_pending_diagnostic)
959 label_text custom_desc
960 = m_pending_diagnostic->describe_return_of_state
961 (evdesc::return_of_state (can_colorize,
962 m_dest_snode->m_fun->decl,
963 m_src_snode->m_fun->decl,
964 m_critical_state));
965 if (custom_desc.get ())
966 return custom_desc;
968 return make_label_text (can_colorize,
969 "returning to %qE from %qE",
970 m_dest_snode->m_fun->decl,
971 m_src_snode->m_fun->decl);
974 /* Implementation of diagnostic_event::get_meaning vfunc for
975 function return events. */
977 diagnostic_event::meaning
978 return_event::get_meaning () const
980 return meaning (VERB_return, NOUN_function);
983 /* Override of checker_event::is_return_p for returns. */
985 bool
986 return_event::is_return_p () const
988 return true;
991 /* class start_consolidated_cfg_edges_event : public checker_event. */
993 label_text
994 start_consolidated_cfg_edges_event::get_desc (bool can_colorize) const
996 return make_label_text (can_colorize,
997 "following %qs branch...",
998 m_edge_sense ? "true" : "false");
1001 /* Implementation of diagnostic_event::get_meaning vfunc for
1002 start_consolidated_cfg_edges_event. */
1004 diagnostic_event::meaning
1005 start_consolidated_cfg_edges_event::get_meaning () const
1007 return meaning (VERB_branch,
1008 (m_edge_sense ? PROPERTY_true : PROPERTY_false));
1011 /* class inlined_call_event : public checker_event. */
1013 label_text
1014 inlined_call_event::get_desc (bool can_colorize) const
1016 return make_label_text (can_colorize,
1017 "inlined call to %qE from %qE",
1018 m_apparent_callee_fndecl,
1019 m_apparent_caller_fndecl);
1022 /* Implementation of diagnostic_event::get_meaning vfunc for
1023 reconstructed inlined function calls. */
1025 diagnostic_event::meaning
1026 inlined_call_event::get_meaning () const
1028 return meaning (VERB_call, NOUN_function);
1031 /* class setjmp_event : public checker_event. */
1033 /* Implementation of diagnostic_event::get_desc vfunc for
1034 setjmp_event. */
1036 label_text
1037 setjmp_event::get_desc (bool can_colorize) const
1039 return make_label_text (can_colorize,
1040 "%qs called here",
1041 get_user_facing_name (m_setjmp_call));
1044 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1046 Record this setjmp's event ID into the path, so that rewind events can
1047 use it. */
1049 void
1050 setjmp_event::prepare_for_emission (checker_path *path,
1051 pending_diagnostic *pd,
1052 diagnostic_event_id_t emission_id)
1054 checker_event::prepare_for_emission (path, pd, emission_id);
1055 path->record_setjmp_event (m_enode, emission_id);
1058 /* class rewind_event : public checker_event. */
1060 /* Get the fndecl containing the site of the longjmp call. */
1062 tree
1063 rewind_event::get_longjmp_caller () const
1065 return m_eedge->m_src->get_function ()->decl;
1068 /* Get the fndecl containing the site of the setjmp call. */
1070 tree
1071 rewind_event::get_setjmp_caller () const
1073 return m_eedge->m_dest->get_function ()->decl;
1076 /* rewind_event's ctor. */
1078 rewind_event::rewind_event (const exploded_edge *eedge,
1079 enum event_kind kind,
1080 const event_loc_info &loc_info,
1081 const rewind_info_t *rewind_info)
1082 : checker_event (kind, loc_info),
1083 m_rewind_info (rewind_info),
1084 m_eedge (eedge)
1086 gcc_assert (m_eedge->m_custom_info.get () == m_rewind_info);
1089 /* class rewind_from_longjmp_event : public rewind_event. */
1091 /* Implementation of diagnostic_event::get_desc vfunc for
1092 rewind_from_longjmp_event. */
1094 label_text
1095 rewind_from_longjmp_event::get_desc (bool can_colorize) const
1097 const char *src_name
1098 = get_user_facing_name (m_rewind_info->get_longjmp_call ());
1100 if (get_longjmp_caller () == get_setjmp_caller ())
1101 /* Special-case: purely intraprocedural rewind. */
1102 return make_label_text (can_colorize,
1103 "rewinding within %qE from %qs...",
1104 get_longjmp_caller (),
1105 src_name);
1106 else
1107 return make_label_text (can_colorize,
1108 "rewinding from %qs in %qE...",
1109 src_name,
1110 get_longjmp_caller ());
1113 /* class rewind_to_setjmp_event : public rewind_event. */
1115 /* Implementation of diagnostic_event::get_desc vfunc for
1116 rewind_to_setjmp_event. */
1118 label_text
1119 rewind_to_setjmp_event::get_desc (bool can_colorize) const
1121 const char *dst_name
1122 = get_user_facing_name (m_rewind_info->get_setjmp_call ());
1124 /* If we can, identify the ID of the setjmp_event. */
1125 if (m_original_setjmp_event_id.known_p ())
1127 if (get_longjmp_caller () == get_setjmp_caller ())
1128 /* Special-case: purely intraprocedural rewind. */
1129 return make_label_text (can_colorize,
1130 "...to %qs (saved at %@)",
1131 dst_name,
1132 &m_original_setjmp_event_id);
1133 else
1134 return make_label_text (can_colorize,
1135 "...to %qs in %qE (saved at %@)",
1136 dst_name,
1137 get_setjmp_caller (),
1138 &m_original_setjmp_event_id);
1140 else
1142 if (get_longjmp_caller () == get_setjmp_caller ())
1143 /* Special-case: purely intraprocedural rewind. */
1144 return make_label_text (can_colorize,
1145 "...to %qs",
1146 dst_name,
1147 get_setjmp_caller ());
1148 else
1149 return make_label_text (can_colorize,
1150 "...to %qs in %qE",
1151 dst_name,
1152 get_setjmp_caller ());
1156 /* Implementation of checker_event::prepare_for_emission vfunc for
1157 rewind_to_setjmp_event.
1159 Attempt to look up the setjmp event ID that recorded the jmp_buf
1160 for this rewind. */
1162 void
1163 rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
1164 pending_diagnostic *pd,
1165 diagnostic_event_id_t emission_id)
1167 checker_event::prepare_for_emission (path, pd, emission_id);
1168 path->get_setjmp_event (m_rewind_info->get_enode_origin (),
1169 &m_original_setjmp_event_id);
1172 /* class warning_event : public checker_event. */
1174 /* Implementation of diagnostic_event::get_desc vfunc for
1175 warning_event.
1177 If the pending diagnostic implements describe_final_event, use it,
1178 generating a precise description e.g.
1179 "second 'free' here; first 'free' was at (7)"
1181 Otherwise generate a generic description. */
1183 label_text
1184 warning_event::get_desc (bool can_colorize) const
1186 if (m_pending_diagnostic)
1188 tree var = fixup_tree_for_diagnostic (m_var);
1189 label_text ev_desc
1190 = m_pending_diagnostic->describe_final_event
1191 (evdesc::final_event (can_colorize, var, m_state, *this));
1192 if (ev_desc.get ())
1194 if (m_sm && flag_analyzer_verbose_state_changes)
1196 if (var)
1197 return make_label_text (can_colorize,
1198 "%s (%qE is in state %qs)",
1199 ev_desc.get (),
1200 var, m_state->get_name ());
1201 else
1202 return make_label_text (can_colorize,
1203 "%s (in global state %qs)",
1204 ev_desc.get (),
1205 m_state->get_name ());
1207 else
1208 return ev_desc;
1212 if (m_sm)
1214 if (m_var)
1215 return make_label_text (can_colorize,
1216 "here (%qE is in state %qs)",
1217 m_var, m_state->get_name ());
1218 else
1219 return make_label_text (can_colorize,
1220 "here (in global state %qs)",
1221 m_state->get_name ());
1223 else
1224 return label_text::borrow ("here");
1227 /* Implementation of diagnostic_event::get_meaning vfunc for
1228 warning_event. */
1230 diagnostic_event::meaning
1231 warning_event::get_meaning () const
1233 return meaning (VERB_danger, NOUN_unknown);
1236 } // namespace ana
1238 #endif /* #if ENABLE_ANALYZER */