libgcc: Fix BIL_TYPE_SIZE == 32 support in _BitInt <-> dfp support
[official-gcc.git] / gcc / analyzer / checker-event.cc
blobb64c58ef77025b40ee10dbe40f01c0fb1a1cfa84
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 #include "system.h"
24 #include "coretypes.h"
25 #include "tree.h"
26 #include "function.h"
27 #include "basic-block.h"
28 #include "gimple.h"
29 #include "diagnostic-core.h"
30 #include "gimple-pretty-print.h"
31 #include "fold-const.h"
32 #include "diagnostic-path.h"
33 #include "options.h"
34 #include "cgraph.h"
35 #include "cfg.h"
36 #include "digraph.h"
37 #include "diagnostic-event-id.h"
38 #include "analyzer/analyzer.h"
39 #include "analyzer/analyzer-logging.h"
40 #include "analyzer/sm.h"
41 #include "sbitmap.h"
42 #include "bitmap.h"
43 #include "ordered-hash-map.h"
44 #include "analyzer/call-string.h"
45 #include "analyzer/program-point.h"
46 #include "analyzer/store.h"
47 #include "analyzer/region-model.h"
48 #include "analyzer/program-state.h"
49 #include "analyzer/checker-path.h"
50 #include "gimple-iterator.h"
51 #include "inlining-iterator.h"
52 #include "analyzer/supergraph.h"
53 #include "analyzer/pending-diagnostic.h"
54 #include "analyzer/diagnostic-manager.h"
55 #include "analyzer/constraint-manager.h"
56 #include "analyzer/checker-event.h"
57 #include "analyzer/exploded-graph.h"
58 #include "diagnostic-format-sarif.h"
59 #include "tree-logical-location.h"
61 #if ENABLE_ANALYZER
63 namespace ana {
65 /* Get a string for EK. */
67 const char *
68 event_kind_to_string (enum event_kind ek)
70 switch (ek)
72 default:
73 gcc_unreachable ();
74 case EK_DEBUG:
75 return "EK_DEBUG";
76 case EK_CUSTOM:
77 return "EK_CUSTOM";
78 case EK_STMT:
79 return "EK_STMT";
80 case EK_REGION_CREATION:
81 return "EK_REGION_CREATION";
82 case EK_FUNCTION_ENTRY:
83 return "EK_FUNCTION_ENTRY";
84 case EK_STATE_CHANGE:
85 return "EK_STATE_CHANGE";
86 case EK_START_CFG_EDGE:
87 return "EK_START_CFG_EDGE";
88 case EK_END_CFG_EDGE:
89 return "EK_END_CFG_EDGE";
90 case EK_CALL_EDGE:
91 return "EK_CALL_EDGE";
92 case EK_RETURN_EDGE:
93 return "EK_RETURN_EDGE";
94 case EK_START_CONSOLIDATED_CFG_EDGES:
95 return "EK_START_CONSOLIDATED_CFG_EDGES";
96 case EK_END_CONSOLIDATED_CFG_EDGES:
97 return "EK_END_CONSOLIDATED_CFG_EDGES";
98 case EK_INLINED_CALL:
99 return "EK_INLINED_CALL";
100 case EK_SETJMP:
101 return "EK_SETJMP";
102 case EK_REWIND_FROM_LONGJMP:
103 return "EK_REWIND_FROM_LONGJMP";
104 case EK_REWIND_TO_SETJMP:
105 return "EK_REWIND_TO_SETJMP";
106 case EK_WARNING:
107 return "EK_WARNING";
111 /* class checker_event : public diagnostic_event. */
113 /* checker_event's ctor. */
115 checker_event::checker_event (enum event_kind kind,
116 const event_loc_info &loc_info)
117 : m_kind (kind), m_loc (loc_info.m_loc),
118 m_original_fndecl (loc_info.m_fndecl),
119 m_effective_fndecl (loc_info.m_fndecl),
120 m_original_depth (loc_info.m_depth),
121 m_effective_depth (loc_info.m_depth),
122 m_pending_diagnostic (NULL), m_emission_id (),
123 m_logical_loc (loc_info.m_fndecl)
125 /* Update effective fndecl and depth if inlining has been recorded. */
126 if (flag_analyzer_undo_inlining)
128 inlining_info info (m_loc);
129 if (info.get_inner_fndecl ())
131 m_effective_fndecl = info.get_inner_fndecl ();
132 m_effective_depth += info.get_extra_frames ();
133 m_logical_loc = tree_logical_location (m_effective_fndecl);
138 /* No-op implementation of diagnostic_event::get_meaning vfunc for
139 checker_event: checker events have no meaning by default. */
141 diagnostic_event::meaning
142 checker_event::get_meaning () const
144 return meaning ();
147 /* Implementation of diagnostic_event::maybe_add_sarif_properties
148 for checker_event. */
150 void
151 checker_event::
152 maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj) const
154 sarif_property_bag &props = thread_flow_loc_obj.get_or_create_properties ();
155 #define PROPERTY_PREFIX "gcc/analyzer/checker_event/"
156 props.set (PROPERTY_PREFIX "emission_id",
157 diagnostic_event_id_to_json (m_emission_id));
158 props.set_string (PROPERTY_PREFIX "kind", event_kind_to_string (m_kind));
160 if (m_original_fndecl != m_effective_fndecl)
162 tree_logical_location logical_loc (m_original_fndecl);
163 props.set (PROPERTY_PREFIX "original_fndecl",
164 make_sarif_logical_location_object (logical_loc));
166 if (m_original_depth != m_effective_depth)
167 props.set_integer (PROPERTY_PREFIX "original_depth", m_original_depth);
168 #undef PROPERTY_PREFIX
171 /* Dump this event to PP (for debugging/logging purposes). */
173 void
174 checker_event::dump (pretty_printer *pp) const
176 label_text event_desc (get_desc (false));
177 pp_printf (pp, "\"%s\" (depth %i",
178 event_desc.get (), m_effective_depth);
180 if (m_effective_depth != m_original_depth)
181 pp_printf (pp, " corrected from %i",
182 m_original_depth);
183 if (m_effective_fndecl)
185 pp_printf (pp, ", fndecl %qE", m_effective_fndecl);
186 if (m_effective_fndecl != m_original_fndecl)
187 pp_printf (pp, " corrected from %qE", m_original_fndecl);
189 pp_printf (pp, ", m_loc=%x)",
190 get_location ());
193 /* Dump this event to stderr (for debugging/logging purposes). */
195 DEBUG_FUNCTION void
196 checker_event::debug () const
198 pretty_printer pp;
199 pp_format_decoder (&pp) = default_tree_printer;
200 pp_show_color (&pp) = pp_show_color (global_dc->printer);
201 pp.buffer->stream = stderr;
202 dump (&pp);
203 pp_newline (&pp);
204 pp_flush (&pp);
207 /* Hook for being notified when this event has its final id EMISSION_ID
208 and is about to emitted for PD.
210 Base implementation of checker_event::prepare_for_emission vfunc;
211 subclasses that override this should chain up to it.
213 Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
214 side-effects of the call to get_desc take place before
215 pending_diagnostic::emit is called.
217 For example, state_change_event::get_desc can call
218 pending_diagnostic::describe_state_change; free_of_non_heap can use this
219 to tweak the message (TODO: would be neater to simply capture the
220 pertinent data within the sm-state). */
222 void
223 checker_event::prepare_for_emission (checker_path *,
224 pending_diagnostic *pd,
225 diagnostic_event_id_t emission_id)
227 m_pending_diagnostic = pd;
228 m_emission_id = emission_id;
230 label_text desc = get_desc (false);
233 /* class debug_event : public checker_event. */
235 /* Implementation of diagnostic_event::get_desc vfunc for
236 debug_event.
237 Use the saved string as the event's description. */
239 label_text
240 debug_event::get_desc (bool) const
242 return label_text::borrow (m_desc);
245 /* class precanned_custom_event : public custom_event. */
247 /* Implementation of diagnostic_event::get_desc vfunc for
248 precanned_custom_event.
249 Use the saved string as the event's description. */
251 label_text
252 precanned_custom_event::get_desc (bool) const
254 return label_text::borrow (m_desc);
257 /* class statement_event : public checker_event. */
259 /* statement_event's ctor. */
261 statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
262 const program_state &dst_state)
263 : checker_event (EK_STMT,
264 event_loc_info (gimple_location (stmt), fndecl, depth)),
265 m_stmt (stmt),
266 m_dst_state (dst_state)
270 /* Implementation of diagnostic_event::get_desc vfunc for
271 statement_event.
272 Use the statement's dump form as the event's description. */
274 label_text
275 statement_event::get_desc (bool) const
277 pretty_printer pp;
278 pp_string (&pp, "stmt: ");
279 pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
280 return label_text::take (xstrdup (pp_formatted_text (&pp)));
283 /* class region_creation_event : public checker_event. */
285 region_creation_event::region_creation_event (const event_loc_info &loc_info)
286 : checker_event (EK_REGION_CREATION, loc_info)
290 /* The various region_creation_event subclasses' get_desc
291 implementations. */
293 label_text
294 region_creation_event_memory_space::get_desc (bool) const
296 switch (m_mem_space)
298 default:
299 return label_text::borrow ("region created here");
300 case MEMSPACE_STACK:
301 return label_text::borrow ("region created on stack here");
302 case MEMSPACE_HEAP:
303 return label_text::borrow ("region created on heap here");
307 label_text
308 region_creation_event_capacity::get_desc (bool can_colorize) const
310 gcc_assert (m_capacity);
311 if (TREE_CODE (m_capacity) == INTEGER_CST)
313 unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
314 return make_label_text_n (can_colorize,
315 hwi,
316 "capacity: %wu byte",
317 "capacity: %wu bytes",
318 hwi);
320 else
321 return make_label_text (can_colorize,
322 "capacity: %qE bytes", m_capacity);
325 label_text
326 region_creation_event_allocation_size::get_desc (bool can_colorize) const
328 if (m_capacity)
330 if (TREE_CODE (m_capacity) == INTEGER_CST)
331 return make_label_text_n (can_colorize,
332 tree_to_uhwi (m_capacity),
333 "allocated %E byte here",
334 "allocated %E bytes here",
335 m_capacity);
336 else
337 return make_label_text (can_colorize,
338 "allocated %qE bytes here",
339 m_capacity);
341 return make_label_text (can_colorize, "allocated here");
344 label_text
345 region_creation_event_debug::get_desc (bool) const
347 pretty_printer pp;
348 pp_format_decoder (&pp) = default_tree_printer;
349 pp_string (&pp, "region creation: ");
350 m_reg->dump_to_pp (&pp, true);
351 if (m_capacity)
352 pp_printf (&pp, " capacity: %qE", m_capacity);
353 return label_text::take (xstrdup (pp_formatted_text (&pp)));
356 /* class function_entry_event : public checker_event. */
358 function_entry_event::function_entry_event (const program_point &dst_point)
359 : checker_event (EK_FUNCTION_ENTRY,
360 event_loc_info (dst_point.get_supernode
361 ()->get_start_location (),
362 dst_point.get_fndecl (),
363 dst_point.get_stack_depth ()))
367 /* Implementation of diagnostic_event::get_desc vfunc for
368 function_entry_event.
370 Use a string such as "entry to 'foo'" as the event's description. */
372 label_text
373 function_entry_event::get_desc (bool can_colorize) const
375 return make_label_text (can_colorize, "entry to %qE", m_effective_fndecl);
378 /* Implementation of diagnostic_event::get_meaning vfunc for
379 function entry. */
381 diagnostic_event::meaning
382 function_entry_event::get_meaning () const
384 return meaning (VERB_enter, NOUN_function);
387 /* class state_change_event : public checker_event. */
389 /* state_change_event's ctor. */
391 state_change_event::state_change_event (const supernode *node,
392 const gimple *stmt,
393 int stack_depth,
394 const state_machine &sm,
395 const svalue *sval,
396 state_machine::state_t from,
397 state_machine::state_t to,
398 const svalue *origin,
399 const program_state &dst_state,
400 const exploded_node *enode)
401 : checker_event (EK_STATE_CHANGE,
402 event_loc_info (stmt->location,
403 node->m_fun->decl,
404 stack_depth)),
405 m_node (node), m_stmt (stmt), m_sm (sm),
406 m_sval (sval), m_from (from), m_to (to),
407 m_origin (origin),
408 m_dst_state (dst_state),
409 m_enode (enode)
413 /* Implementation of diagnostic_event::get_desc vfunc for
414 state_change_event.
416 Attempt to generate a nicer human-readable description.
417 For greatest precision-of-wording, give the pending diagnostic
418 a chance to describe this state change (in terms of the
419 diagnostic).
420 Note that we only have a pending_diagnostic set on the event once
421 the diagnostic is about to being emitted, so the description for
422 an event can change. */
424 label_text
425 state_change_event::get_desc (bool can_colorize) const
427 if (m_pending_diagnostic)
429 region_model *model = m_dst_state.m_region_model;
430 tree var = model->get_representative_tree (m_sval);
431 tree origin = model->get_representative_tree (m_origin);
432 label_text custom_desc
433 = m_pending_diagnostic->describe_state_change
434 (evdesc::state_change (can_colorize, var, origin,
435 m_from, m_to, m_emission_id, *this));
436 if (custom_desc.get ())
438 if (flag_analyzer_verbose_state_changes)
440 /* Get any "meaning" of event. */
441 diagnostic_event::meaning meaning = get_meaning ();
442 pretty_printer meaning_pp;
443 meaning.dump_to_pp (&meaning_pp);
445 /* Append debug version. */
446 if (var)
448 if (m_origin)
449 return make_label_text
450 (can_colorize,
451 "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
452 custom_desc.get (),
453 var,
454 m_from->get_name (),
455 m_to->get_name (),
456 origin,
457 pp_formatted_text (&meaning_pp));
458 else
459 return make_label_text
460 (can_colorize,
461 "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
462 custom_desc.get (),
463 var,
464 m_from->get_name (),
465 m_to->get_name (),
466 pp_formatted_text (&meaning_pp));
468 else
470 if (m_origin)
471 return make_label_text
472 (can_colorize,
473 "%s (state: %qs -> %qs, origin: %qE, meaning: %s)",
474 custom_desc.get (),
475 m_from->get_name (),
476 m_to->get_name (),
477 origin,
478 pp_formatted_text (&meaning_pp));
479 else
480 return make_label_text
481 (can_colorize,
482 "%s (state: %qs -> %qs, NULL origin, meaning: %s)",
483 custom_desc.get (),
484 m_from->get_name (),
485 m_to->get_name (),
486 pp_formatted_text (&meaning_pp));
489 else
490 return custom_desc;
494 /* Fallback description. */
495 if (m_sval)
497 label_text sval_desc = m_sval->get_desc ();
498 if (m_origin)
500 label_text origin_desc = m_origin->get_desc ();
501 return make_label_text
502 (can_colorize,
503 "state of %qs: %qs -> %qs (origin: %qs)",
504 sval_desc.get (),
505 m_from->get_name (),
506 m_to->get_name (),
507 origin_desc.get ());
509 else
510 return make_label_text
511 (can_colorize,
512 "state of %qs: %qs -> %qs (NULL origin)",
513 sval_desc.get (),
514 m_from->get_name (),
515 m_to->get_name ());
517 else
519 gcc_assert (m_origin == NULL);
520 return make_label_text
521 (can_colorize,
522 "global state: %qs -> %qs",
523 m_from->get_name (),
524 m_to->get_name ());
528 /* Implementation of diagnostic_event::get_meaning vfunc for
529 state change events: delegate to the pending_diagnostic to
530 get any meaning. */
532 diagnostic_event::meaning
533 state_change_event::get_meaning () const
535 if (m_pending_diagnostic)
537 region_model *model = m_dst_state.m_region_model;
538 tree var = model->get_representative_tree (m_sval);
539 tree origin = model->get_representative_tree (m_origin);
540 return m_pending_diagnostic->get_meaning_for_state_change
541 (evdesc::state_change (false, var, origin,
542 m_from, m_to, m_emission_id, *this));
544 else
545 return meaning ();
548 /* class superedge_event : public checker_event. */
550 /* Implementation of diagnostic_event::maybe_add_sarif_properties
551 for superedge_event. */
553 void
554 superedge_event::maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj)
555 const
557 checker_event::maybe_add_sarif_properties (thread_flow_loc_obj);
558 sarif_property_bag &props = thread_flow_loc_obj.get_or_create_properties ();
559 #define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
560 if (m_sedge)
561 props.set (PROPERTY_PREFIX "superedge", m_sedge->to_json ());
562 #undef PROPERTY_PREFIX
565 /* Get the callgraph_superedge for this superedge_event, which must be
566 for an interprocedural edge, rather than a CFG edge. */
568 const callgraph_superedge&
569 superedge_event::get_callgraph_superedge () const
571 gcc_assert (m_sedge->m_kind != SUPEREDGE_CFG_EDGE);
572 return *m_sedge->dyn_cast_callgraph_superedge ();
575 /* Determine if this event should be filtered at the given verbosity
576 level. */
578 bool
579 superedge_event::should_filter_p (int verbosity) const
581 switch (m_sedge->m_kind)
583 case SUPEREDGE_CFG_EDGE:
585 if (verbosity < 2)
586 return true;
588 if (verbosity < 4)
590 /* Filter events with empty descriptions. This ought to filter
591 FALLTHRU, but retain true/false/switch edges. */
592 label_text desc = get_desc (false);
593 gcc_assert (desc.get ());
594 if (desc.get ()[0] == '\0')
595 return true;
598 break;
600 default:
601 break;
603 return false;
606 /* superedge_event's ctor. */
608 superedge_event::superedge_event (enum event_kind kind,
609 const exploded_edge &eedge,
610 const event_loc_info &loc_info)
611 : checker_event (kind, loc_info),
612 m_eedge (eedge), m_sedge (eedge.m_sedge),
613 m_var (NULL_TREE), m_critical_state (0)
615 /* Note that m_sedge can be nullptr for e.g. jumps through
616 function pointers. */
619 /* class cfg_edge_event : public superedge_event. */
621 /* Get the cfg_superedge for this cfg_edge_event. */
623 const cfg_superedge &
624 cfg_edge_event::get_cfg_superedge () const
626 return *m_sedge->dyn_cast_cfg_superedge ();
629 /* cfg_edge_event's ctor. */
631 cfg_edge_event::cfg_edge_event (enum event_kind kind,
632 const exploded_edge &eedge,
633 const event_loc_info &loc_info)
634 : superedge_event (kind, eedge, loc_info)
636 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
639 /* Implementation of diagnostic_event::get_meaning vfunc for
640 CFG edge events. */
642 diagnostic_event::meaning
643 cfg_edge_event::get_meaning () const
645 const cfg_superedge& cfg_sedge = get_cfg_superedge ();
646 if (cfg_sedge.true_value_p ())
647 return meaning (VERB_branch, PROPERTY_true);
648 else if (cfg_sedge.false_value_p ())
649 return meaning (VERB_branch, PROPERTY_false);
650 else
651 return meaning ();
654 /* class start_cfg_edge_event : public cfg_edge_event. */
656 /* Implementation of diagnostic_event::get_desc vfunc for
657 start_cfg_edge_event.
659 If -fanalyzer-verbose-edges, then generate low-level descriptions, such
661 "taking 'true' edge SN:7 -> SN:8".
663 Otherwise, generate strings using the label of the underlying CFG if
664 any, such as:
665 "following 'true' branch..." or
666 "following 'case 3' branch..."
667 "following 'default' branch..."
669 For conditionals, attempt to supply a description of the condition that
670 holds, such as:
671 "following 'false' branch (when 'ptr' is non-NULL)..."
673 Failing that, return an empty description (which will lead to this event
674 being filtered). */
676 label_text
677 start_cfg_edge_event::get_desc (bool can_colorize) const
679 bool user_facing = !flag_analyzer_verbose_edges;
680 label_text edge_desc (m_sedge->get_description (user_facing));
681 if (user_facing)
683 if (edge_desc.get () && strlen (edge_desc.get ()) > 0)
685 label_text cond_desc = maybe_describe_condition (can_colorize);
686 label_text result;
687 if (cond_desc.get ())
688 return make_label_text (can_colorize,
689 "following %qs branch (%s)...",
690 edge_desc.get (), cond_desc.get ());
691 else
692 return make_label_text (can_colorize,
693 "following %qs branch...",
694 edge_desc.get ());
696 else
697 return label_text::borrow ("");
699 else
701 if (strlen (edge_desc.get ()) > 0)
702 return make_label_text (can_colorize,
703 "taking %qs edge SN:%i -> SN:%i",
704 edge_desc.get (),
705 m_sedge->m_src->m_index,
706 m_sedge->m_dest->m_index);
707 else
708 return make_label_text (can_colorize,
709 "taking edge SN:%i -> SN:%i",
710 m_sedge->m_src->m_index,
711 m_sedge->m_dest->m_index);
715 /* Attempt to generate a description of any condition that holds at this edge.
717 The intent is to make the user-facing messages more clear, especially for
718 cases where there's a single or double-negative, such as
719 when describing the false branch of an inverted condition.
721 For example, rather than printing just:
723 | if (!ptr)
726 | (1) following 'false' branch...
728 it's clearer to spell out the condition that holds:
730 | if (!ptr)
733 | (1) following 'false' branch (when 'ptr' is non-NULL)...
734 ^^^^^^^^^^^^^^^^^^^^^^
736 In the above example, this function would generate the highlighted
737 string: "when 'ptr' is non-NULL".
739 If the edge is not a condition, or it's not clear that a description of
740 the condition would be helpful to the user, return NULL. */
742 label_text
743 start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const
745 const cfg_superedge& cfg_sedge = get_cfg_superedge ();
747 if (cfg_sedge.true_value_p () || cfg_sedge.false_value_p ())
749 const gimple *last_stmt = m_sedge->m_src->get_last_stmt ();
750 if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
752 enum tree_code op = gimple_cond_code (cond_stmt);
753 tree lhs = gimple_cond_lhs (cond_stmt);
754 tree rhs = gimple_cond_rhs (cond_stmt);
755 if (cfg_sedge.false_value_p ())
756 op = invert_tree_comparison (op, false /* honor_nans */);
757 return maybe_describe_condition (can_colorize,
758 lhs, op, rhs);
761 return label_text::borrow (NULL);
764 /* Subroutine of maybe_describe_condition above.
766 Attempt to generate a user-facing description of the condition
767 LHS OP RHS, but only if it is likely to make it easier for the
768 user to understand a condition. */
770 label_text
771 start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
772 tree lhs,
773 enum tree_code op,
774 tree rhs)
776 /* In theory we could just build a tree via
777 fold_build2 (op, boolean_type_node, lhs, rhs)
778 and print it with %qE on it, but this leads to warts such as
779 parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
781 /* Special-case: describe testing the result of strcmp, as figuring
782 out what the "true" or "false" path is can be confusing to the user. */
783 if (TREE_CODE (lhs) == SSA_NAME
784 && zerop (rhs))
786 if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
787 if (is_special_named_call_p (call, "strcmp", 2))
789 if (op == EQ_EXPR)
790 return label_text::borrow ("when the strings are equal");
791 if (op == NE_EXPR)
792 return label_text::borrow ("when the strings are non-equal");
796 /* Only attempt to generate text for sufficiently simple expressions. */
797 if (!should_print_expr_p (lhs))
798 return label_text::borrow (NULL);
799 if (!should_print_expr_p (rhs))
800 return label_text::borrow (NULL);
802 /* Special cases for pointer comparisons against NULL. */
803 if (POINTER_TYPE_P (TREE_TYPE (lhs))
804 && POINTER_TYPE_P (TREE_TYPE (rhs))
805 && zerop (rhs))
807 if (op == EQ_EXPR)
808 return make_label_text (can_colorize, "when %qE is NULL",
809 lhs);
810 if (op == NE_EXPR)
811 return make_label_text (can_colorize, "when %qE is non-NULL",
812 lhs);
815 return make_label_text (can_colorize, "when %<%E %s %E%>",
816 lhs, op_symbol_code (op), rhs);
819 /* Subroutine of maybe_describe_condition.
821 Return true if EXPR is we will get suitable user-facing output
822 from %E on it. */
824 bool
825 start_cfg_edge_event::should_print_expr_p (tree expr)
827 if (TREE_CODE (expr) == SSA_NAME)
829 if (SSA_NAME_VAR (expr))
830 return should_print_expr_p (SSA_NAME_VAR (expr));
831 else
832 return false;
835 if (DECL_P (expr))
836 return true;
838 if (CONSTANT_CLASS_P (expr))
839 return true;
841 return false;
844 /* class call_event : public superedge_event. */
846 /* call_event's ctor. */
848 call_event::call_event (const exploded_edge &eedge,
849 const event_loc_info &loc_info)
850 : superedge_event (EK_CALL_EDGE, eedge, loc_info)
852 if (eedge.m_sedge)
853 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
855 m_src_snode = eedge.m_src->get_supernode ();
856 m_dest_snode = eedge.m_dest->get_supernode ();
859 /* Implementation of diagnostic_event::get_desc vfunc for
860 call_event.
862 If this call event passes critical state for an sm-based warning,
863 allow the diagnostic to generate a precise description, such as:
865 "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
867 Otherwise, generate a description of the form
868 "calling 'foo' from 'bar'". */
870 label_text
871 call_event::get_desc (bool can_colorize) const
873 if (m_critical_state && m_pending_diagnostic)
875 gcc_assert (m_var);
876 tree var = fixup_tree_for_diagnostic (m_var);
877 label_text custom_desc
878 = m_pending_diagnostic->describe_call_with_state
879 (evdesc::call_with_state (can_colorize,
880 m_src_snode->m_fun->decl,
881 m_dest_snode->m_fun->decl,
882 var,
883 m_critical_state));
884 if (custom_desc.get ())
885 return custom_desc;
888 return make_label_text (can_colorize,
889 "calling %qE from %qE",
890 get_callee_fndecl (),
891 get_caller_fndecl ());
894 /* Implementation of diagnostic_event::get_meaning vfunc for
895 function call events. */
897 diagnostic_event::meaning
898 call_event::get_meaning () const
900 return meaning (VERB_call, NOUN_function);
903 /* Override of checker_event::is_call_p for calls. */
905 bool
906 call_event::is_call_p () const
908 return true;
911 tree
912 call_event::get_caller_fndecl () const
914 return m_src_snode->m_fun->decl;
917 tree
918 call_event::get_callee_fndecl () const
920 return m_dest_snode->m_fun->decl;
923 /* class return_event : public superedge_event. */
925 /* return_event's ctor. */
927 return_event::return_event (const exploded_edge &eedge,
928 const event_loc_info &loc_info)
929 : superedge_event (EK_RETURN_EDGE, eedge, loc_info)
931 if (eedge.m_sedge)
932 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
934 m_src_snode = eedge.m_src->get_supernode ();
935 m_dest_snode = eedge.m_dest->get_supernode ();
938 /* Implementation of diagnostic_event::get_desc vfunc for
939 return_event.
941 If this return event returns critical state for an sm-based warning,
942 allow the diagnostic to generate a precise description, such as:
944 "possible of NULL to 'foo' from 'bar'"
946 Otherwise, generate a description of the form
947 "returning to 'foo' from 'bar'. */
949 label_text
950 return_event::get_desc (bool can_colorize) const
952 /* For greatest precision-of-wording, if this is returning the
953 state involved in the pending diagnostic, give the pending
954 diagnostic a chance to describe this return (in terms of
955 itself). */
956 if (m_critical_state && m_pending_diagnostic)
958 label_text custom_desc
959 = m_pending_diagnostic->describe_return_of_state
960 (evdesc::return_of_state (can_colorize,
961 m_dest_snode->m_fun->decl,
962 m_src_snode->m_fun->decl,
963 m_critical_state));
964 if (custom_desc.get ())
965 return custom_desc;
967 return make_label_text (can_colorize,
968 "returning to %qE from %qE",
969 m_dest_snode->m_fun->decl,
970 m_src_snode->m_fun->decl);
973 /* Implementation of diagnostic_event::get_meaning vfunc for
974 function return events. */
976 diagnostic_event::meaning
977 return_event::get_meaning () const
979 return meaning (VERB_return, NOUN_function);
982 /* Override of checker_event::is_return_p for returns. */
984 bool
985 return_event::is_return_p () const
987 return true;
990 /* class start_consolidated_cfg_edges_event : public checker_event. */
992 label_text
993 start_consolidated_cfg_edges_event::get_desc (bool can_colorize) const
995 return make_label_text (can_colorize,
996 "following %qs branch...",
997 m_edge_sense ? "true" : "false");
1000 /* Implementation of diagnostic_event::get_meaning vfunc for
1001 start_consolidated_cfg_edges_event. */
1003 diagnostic_event::meaning
1004 start_consolidated_cfg_edges_event::get_meaning () const
1006 return meaning (VERB_branch,
1007 (m_edge_sense ? PROPERTY_true : PROPERTY_false));
1010 /* class inlined_call_event : public checker_event. */
1012 label_text
1013 inlined_call_event::get_desc (bool can_colorize) const
1015 return make_label_text (can_colorize,
1016 "inlined call to %qE from %qE",
1017 m_apparent_callee_fndecl,
1018 m_apparent_caller_fndecl);
1021 /* Implementation of diagnostic_event::get_meaning vfunc for
1022 reconstructed inlined function calls. */
1024 diagnostic_event::meaning
1025 inlined_call_event::get_meaning () const
1027 return meaning (VERB_call, NOUN_function);
1030 /* class setjmp_event : public checker_event. */
1032 /* Implementation of diagnostic_event::get_desc vfunc for
1033 setjmp_event. */
1035 label_text
1036 setjmp_event::get_desc (bool can_colorize) const
1038 return make_label_text (can_colorize,
1039 "%qs called here",
1040 get_user_facing_name (m_setjmp_call));
1043 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1045 Record this setjmp's event ID into the path, so that rewind events can
1046 use it. */
1048 void
1049 setjmp_event::prepare_for_emission (checker_path *path,
1050 pending_diagnostic *pd,
1051 diagnostic_event_id_t emission_id)
1053 checker_event::prepare_for_emission (path, pd, emission_id);
1054 path->record_setjmp_event (m_enode, emission_id);
1057 /* class rewind_event : public checker_event. */
1059 /* Get the fndecl containing the site of the longjmp call. */
1061 tree
1062 rewind_event::get_longjmp_caller () const
1064 return m_eedge->m_src->get_function ()->decl;
1067 /* Get the fndecl containing the site of the setjmp call. */
1069 tree
1070 rewind_event::get_setjmp_caller () const
1072 return m_eedge->m_dest->get_function ()->decl;
1075 /* rewind_event's ctor. */
1077 rewind_event::rewind_event (const exploded_edge *eedge,
1078 enum event_kind kind,
1079 const event_loc_info &loc_info,
1080 const rewind_info_t *rewind_info)
1081 : checker_event (kind, loc_info),
1082 m_rewind_info (rewind_info),
1083 m_eedge (eedge)
1085 gcc_assert (m_eedge->m_custom_info.get () == m_rewind_info);
1088 /* class rewind_from_longjmp_event : public rewind_event. */
1090 /* Implementation of diagnostic_event::get_desc vfunc for
1091 rewind_from_longjmp_event. */
1093 label_text
1094 rewind_from_longjmp_event::get_desc (bool can_colorize) const
1096 const char *src_name
1097 = get_user_facing_name (m_rewind_info->get_longjmp_call ());
1099 if (get_longjmp_caller () == get_setjmp_caller ())
1100 /* Special-case: purely intraprocedural rewind. */
1101 return make_label_text (can_colorize,
1102 "rewinding within %qE from %qs...",
1103 get_longjmp_caller (),
1104 src_name);
1105 else
1106 return make_label_text (can_colorize,
1107 "rewinding from %qs in %qE...",
1108 src_name,
1109 get_longjmp_caller ());
1112 /* class rewind_to_setjmp_event : public rewind_event. */
1114 /* Implementation of diagnostic_event::get_desc vfunc for
1115 rewind_to_setjmp_event. */
1117 label_text
1118 rewind_to_setjmp_event::get_desc (bool can_colorize) const
1120 const char *dst_name
1121 = get_user_facing_name (m_rewind_info->get_setjmp_call ());
1123 /* If we can, identify the ID of the setjmp_event. */
1124 if (m_original_setjmp_event_id.known_p ())
1126 if (get_longjmp_caller () == get_setjmp_caller ())
1127 /* Special-case: purely intraprocedural rewind. */
1128 return make_label_text (can_colorize,
1129 "...to %qs (saved at %@)",
1130 dst_name,
1131 &m_original_setjmp_event_id);
1132 else
1133 return make_label_text (can_colorize,
1134 "...to %qs in %qE (saved at %@)",
1135 dst_name,
1136 get_setjmp_caller (),
1137 &m_original_setjmp_event_id);
1139 else
1141 if (get_longjmp_caller () == get_setjmp_caller ())
1142 /* Special-case: purely intraprocedural rewind. */
1143 return make_label_text (can_colorize,
1144 "...to %qs",
1145 dst_name,
1146 get_setjmp_caller ());
1147 else
1148 return make_label_text (can_colorize,
1149 "...to %qs in %qE",
1150 dst_name,
1151 get_setjmp_caller ());
1155 /* Implementation of checker_event::prepare_for_emission vfunc for
1156 rewind_to_setjmp_event.
1158 Attempt to look up the setjmp event ID that recorded the jmp_buf
1159 for this rewind. */
1161 void
1162 rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
1163 pending_diagnostic *pd,
1164 diagnostic_event_id_t emission_id)
1166 checker_event::prepare_for_emission (path, pd, emission_id);
1167 path->get_setjmp_event (m_rewind_info->get_enode_origin (),
1168 &m_original_setjmp_event_id);
1171 /* class warning_event : public checker_event. */
1173 /* Implementation of diagnostic_event::get_desc vfunc for
1174 warning_event.
1176 If the pending diagnostic implements describe_final_event, use it,
1177 generating a precise description e.g.
1178 "second 'free' here; first 'free' was at (7)"
1180 Otherwise generate a generic description. */
1182 label_text
1183 warning_event::get_desc (bool can_colorize) const
1185 if (m_pending_diagnostic)
1187 tree var = fixup_tree_for_diagnostic (m_var);
1188 label_text ev_desc
1189 = m_pending_diagnostic->describe_final_event
1190 (evdesc::final_event (can_colorize, var, m_state, *this));
1191 if (ev_desc.get ())
1193 if (m_sm && flag_analyzer_verbose_state_changes)
1195 if (var)
1196 return make_label_text (can_colorize,
1197 "%s (%qE is in state %qs)",
1198 ev_desc.get (),
1199 var, m_state->get_name ());
1200 else
1201 return make_label_text (can_colorize,
1202 "%s (in global state %qs)",
1203 ev_desc.get (),
1204 m_state->get_name ());
1206 else
1207 return ev_desc;
1211 if (m_sm)
1213 if (m_var)
1214 return make_label_text (can_colorize,
1215 "here (%qE is in state %qs)",
1216 m_var, m_state->get_name ());
1217 else
1218 return make_label_text (can_colorize,
1219 "here (in global state %qs)",
1220 m_state->get_name ());
1222 else
1223 return label_text::borrow ("here");
1226 /* Implementation of diagnostic_event::get_meaning vfunc for
1227 warning_event. */
1229 diagnostic_event::meaning
1230 warning_event::get_meaning () const
1232 return meaning (VERB_danger, NOUN_unknown);
1235 } // namespace ana
1237 #endif /* #if ENABLE_ANALYZER */