1 /* Subclasses of diagnostic_event for analyzer diagnostics.
2 Copyright (C) 2019-2022 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)
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/>. */
22 #define INCLUDE_MEMORY
24 #include "coretypes.h"
27 #include "basic-block.h"
29 #include "diagnostic-core.h"
30 #include "gimple-pretty-print.h"
31 #include "fold-const.h"
32 #include "diagnostic-path.h"
37 #include "diagnostic-event-id.h"
38 #include "analyzer/analyzer.h"
39 #include "analyzer/analyzer-logging.h"
40 #include "analyzer/sm.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"
63 /* Get a string for EK. */
66 event_kind_to_string (enum event_kind ek)
78 case EK_REGION_CREATION:
79 return "EK_REGION_CREATION";
80 case EK_FUNCTION_ENTRY:
81 return "EK_FUNCTION_ENTRY";
83 return "EK_STATE_CHANGE";
84 case EK_START_CFG_EDGE:
85 return "EK_START_CFG_EDGE";
87 return "EK_END_CFG_EDGE";
89 return "EK_CALL_EDGE";
91 return "EK_RETURN_EDGE";
92 case EK_START_CONSOLIDATED_CFG_EDGES:
93 return "EK_START_CONSOLIDATED_CFG_EDGES";
94 case EK_END_CONSOLIDATED_CFG_EDGES:
95 return "EK_END_CONSOLIDATED_CFG_EDGES";
97 return "EK_INLINED_CALL";
100 case EK_REWIND_FROM_LONGJMP:
101 return "EK_REWIND_FROM_LONGJMP";
102 case EK_REWIND_TO_SETJMP:
103 return "EK_REWIND_TO_SETJMP";
109 /* A class for fixing up fndecls and stack depths in checker_event, based
112 The early inliner runs before the analyzer, which can lead to confusing
115 Tne base fndecl and depth within a checker_event are from call strings
116 in program_points, which reflect the call strings after inlining.
117 This class lets us offset the depth and fix up the reported fndecl and
118 stack depth to better reflect the user's original code. */
123 inlining_info (location_t loc)
125 inlining_iterator iter (loc);
126 m_inner_fndecl = iter.get_fndecl ();
128 while (!iter.done_p ())
130 m_outer_fndecl = iter.get_fndecl ();
135 m_extra_frames = num_frames - 1;
140 tree get_inner_fndecl () const { return m_inner_fndecl; }
141 int get_extra_frames () const { return m_extra_frames; }
149 /* class checker_event : public diagnostic_event. */
151 /* checker_event's ctor. */
153 checker_event::checker_event (enum event_kind kind,
154 const event_loc_info &loc_info)
155 : m_kind (kind), m_loc (loc_info.m_loc),
156 m_original_fndecl (loc_info.m_fndecl),
157 m_effective_fndecl (loc_info.m_fndecl),
158 m_original_depth (loc_info.m_depth),
159 m_effective_depth (loc_info.m_depth),
160 m_pending_diagnostic (NULL), m_emission_id (),
161 m_logical_loc (loc_info.m_fndecl)
163 /* Update effective fndecl and depth if inlining has been recorded. */
164 if (flag_analyzer_undo_inlining)
166 inlining_info info (m_loc);
167 if (info.get_inner_fndecl ())
169 m_effective_fndecl = info.get_inner_fndecl ();
170 m_effective_depth += info.get_extra_frames ();
171 m_logical_loc = tree_logical_location (m_effective_fndecl);
176 /* No-op implementation of diagnostic_event::get_meaning vfunc for
177 checker_event: checker events have no meaning by default. */
179 diagnostic_event::meaning
180 checker_event::get_meaning () const
185 /* Dump this event to PP (for debugging/logging purposes). */
188 checker_event::dump (pretty_printer *pp) const
190 label_text event_desc (get_desc (false));
191 pp_printf (pp, "\"%s\" (depth %i",
192 event_desc.get (), m_effective_depth);
194 if (m_effective_depth != m_original_depth)
195 pp_printf (pp, " corrected from %i",
197 if (m_effective_fndecl)
199 pp_printf (pp, ", fndecl %qE", m_effective_fndecl);
200 if (m_effective_fndecl != m_original_fndecl)
201 pp_printf (pp, " corrected from %qE", m_original_fndecl);
203 pp_printf (pp, ", m_loc=%x)",
207 /* Dump this event to stderr (for debugging/logging purposes). */
210 checker_event::debug () const
213 pp_format_decoder (&pp) = default_tree_printer;
214 pp_show_color (&pp) = pp_show_color (global_dc->printer);
215 pp.buffer->stream = stderr;
221 /* Hook for being notified when this event has its final id EMISSION_ID
222 and is about to emitted for PD.
224 Base implementation of checker_event::prepare_for_emission vfunc;
225 subclasses that override this should chain up to it.
227 Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
228 side-effects of the call to get_desc take place before
229 pending_diagnostic::emit is called.
231 For example, state_change_event::get_desc can call
232 pending_diagnostic::describe_state_change; free_of_non_heap can use this
233 to tweak the message (TODO: would be neater to simply capture the
234 pertinent data within the sm-state). */
237 checker_event::prepare_for_emission (checker_path *,
238 pending_diagnostic *pd,
239 diagnostic_event_id_t emission_id)
241 m_pending_diagnostic = pd;
242 m_emission_id = emission_id;
244 label_text desc = get_desc (false);
247 /* class debug_event : public checker_event. */
249 /* Implementation of diagnostic_event::get_desc vfunc for
251 Use the saved string as the event's description. */
254 debug_event::get_desc (bool) const
256 return label_text::borrow (m_desc);
259 /* class precanned_custom_event : public custom_event. */
261 /* Implementation of diagnostic_event::get_desc vfunc for
262 precanned_custom_event.
263 Use the saved string as the event's description. */
266 precanned_custom_event::get_desc (bool) const
268 return label_text::borrow (m_desc);
271 /* class statement_event : public checker_event. */
273 /* statement_event's ctor. */
275 statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
276 const program_state &dst_state)
277 : checker_event (EK_STMT,
278 event_loc_info (gimple_location (stmt), fndecl, depth)),
280 m_dst_state (dst_state)
284 /* Implementation of diagnostic_event::get_desc vfunc for
286 Use the statement's dump form as the event's description. */
289 statement_event::get_desc (bool) const
292 pp_string (&pp, "stmt: ");
293 pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
294 return label_text::take (xstrdup (pp_formatted_text (&pp)));
297 /* class region_creation_event : public checker_event. */
299 region_creation_event::region_creation_event (const event_loc_info &loc_info)
300 : checker_event (EK_REGION_CREATION, loc_info)
304 /* The various region_creation_event subclasses' get_desc
308 region_creation_event_memory_space::get_desc (bool) const
313 return label_text::borrow ("region created here");
315 return label_text::borrow ("region created on stack here");
317 return label_text::borrow ("region created on heap here");
322 region_creation_event_capacity::get_desc (bool can_colorize) const
324 gcc_assert (m_capacity);
325 if (TREE_CODE (m_capacity) == INTEGER_CST)
327 unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
328 return make_label_text_n (can_colorize,
330 "capacity: %wu byte",
331 "capacity: %wu bytes",
335 return make_label_text (can_colorize,
336 "capacity: %qE bytes", m_capacity);
340 region_creation_event_allocation_size::get_desc (bool can_colorize) const
344 if (TREE_CODE (m_capacity) == INTEGER_CST)
345 return make_label_text_n (can_colorize,
346 tree_to_uhwi (m_capacity),
347 "allocated %E byte here",
348 "allocated %E bytes here",
351 return make_label_text (can_colorize,
352 "allocated %qE bytes here",
355 return make_label_text (can_colorize, "allocated here");
359 region_creation_event_debug::get_desc (bool) const
362 pp_format_decoder (&pp) = default_tree_printer;
363 pp_string (&pp, "region creation: ");
364 m_reg->dump_to_pp (&pp, true);
366 pp_printf (&pp, " capacity: %qE", m_capacity);
367 return label_text::take (xstrdup (pp_formatted_text (&pp)));
370 /* class function_entry_event : public checker_event. */
372 function_entry_event::function_entry_event (const program_point &dst_point)
373 : checker_event (EK_FUNCTION_ENTRY,
374 event_loc_info (dst_point.get_supernode
375 ()->get_start_location (),
376 dst_point.get_fndecl (),
377 dst_point.get_stack_depth ()))
381 /* Implementation of diagnostic_event::get_desc vfunc for
382 function_entry_event.
384 Use a string such as "entry to 'foo'" as the event's description. */
387 function_entry_event::get_desc (bool can_colorize) const
389 return make_label_text (can_colorize, "entry to %qE", m_effective_fndecl);
392 /* Implementation of diagnostic_event::get_meaning vfunc for
395 diagnostic_event::meaning
396 function_entry_event::get_meaning () const
398 return meaning (VERB_enter, NOUN_function);
401 /* class state_change_event : public checker_event. */
403 /* state_change_event's ctor. */
405 state_change_event::state_change_event (const supernode *node,
408 const state_machine &sm,
410 state_machine::state_t from,
411 state_machine::state_t to,
412 const svalue *origin,
413 const program_state &dst_state)
414 : checker_event (EK_STATE_CHANGE,
415 event_loc_info (stmt->location,
418 m_node (node), m_stmt (stmt), m_sm (sm),
419 m_sval (sval), m_from (from), m_to (to),
421 m_dst_state (dst_state)
425 /* Implementation of diagnostic_event::get_desc vfunc for
428 Attempt to generate a nicer human-readable description.
429 For greatest precision-of-wording, give the pending diagnostic
430 a chance to describe this state change (in terms of the
432 Note that we only have a pending_diagnostic set on the event once
433 the diagnostic is about to being emitted, so the description for
434 an event can change. */
437 state_change_event::get_desc (bool can_colorize) const
439 if (m_pending_diagnostic)
441 region_model *model = m_dst_state.m_region_model;
442 tree var = model->get_representative_tree (m_sval);
443 tree origin = model->get_representative_tree (m_origin);
444 label_text custom_desc
445 = m_pending_diagnostic->describe_state_change
446 (evdesc::state_change (can_colorize, var, origin,
447 m_from, m_to, m_emission_id, *this));
448 if (custom_desc.get ())
450 if (flag_analyzer_verbose_state_changes)
452 /* Get any "meaning" of event. */
453 diagnostic_event::meaning meaning = get_meaning ();
454 pretty_printer meaning_pp;
455 meaning.dump_to_pp (&meaning_pp);
457 /* Append debug version. */
459 return make_label_text
461 "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
467 pp_formatted_text (&meaning_pp));
469 return make_label_text
471 "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
476 pp_formatted_text (&meaning_pp));
483 /* Fallback description. */
486 label_text sval_desc = m_sval->get_desc ();
489 label_text origin_desc = m_origin->get_desc ();
490 return make_label_text
492 "state of %qs: %qs -> %qs (origin: %qs)",
499 return make_label_text
501 "state of %qs: %qs -> %qs (NULL origin)",
508 gcc_assert (m_origin == NULL);
509 return make_label_text
511 "global state: %qs -> %qs",
517 /* Implementation of diagnostic_event::get_meaning vfunc for
518 state change events: delegate to the pending_diagnostic to
521 diagnostic_event::meaning
522 state_change_event::get_meaning () const
524 if (m_pending_diagnostic)
526 region_model *model = m_dst_state.m_region_model;
527 tree var = model->get_representative_tree (m_sval);
528 tree origin = model->get_representative_tree (m_origin);
529 return m_pending_diagnostic->get_meaning_for_state_change
530 (evdesc::state_change (false, var, origin,
531 m_from, m_to, m_emission_id, *this));
537 /* class superedge_event : public checker_event. */
539 /* Get the callgraph_superedge for this superedge_event, which must be
540 for an interprocedural edge, rather than a CFG edge. */
542 const callgraph_superedge&
543 superedge_event::get_callgraph_superedge () const
545 gcc_assert (m_sedge->m_kind != SUPEREDGE_CFG_EDGE);
546 return *m_sedge->dyn_cast_callgraph_superedge ();
549 /* Determine if this event should be filtered at the given verbosity
553 superedge_event::should_filter_p (int verbosity) const
555 switch (m_sedge->m_kind)
557 case SUPEREDGE_CFG_EDGE:
564 /* Filter events with empty descriptions. This ought to filter
565 FALLTHRU, but retain true/false/switch edges. */
566 label_text desc = get_desc (false);
567 gcc_assert (desc.get ());
568 if (desc.get ()[0] == '\0')
580 /* superedge_event's ctor. */
582 superedge_event::superedge_event (enum event_kind kind,
583 const exploded_edge &eedge,
584 const event_loc_info &loc_info)
585 : checker_event (kind, loc_info),
586 m_eedge (eedge), m_sedge (eedge.m_sedge),
587 m_var (NULL_TREE), m_critical_state (0)
591 /* class cfg_edge_event : public superedge_event. */
593 /* Get the cfg_superedge for this cfg_edge_event. */
595 const cfg_superedge &
596 cfg_edge_event::get_cfg_superedge () const
598 return *m_sedge->dyn_cast_cfg_superedge ();
601 /* cfg_edge_event's ctor. */
603 cfg_edge_event::cfg_edge_event (enum event_kind kind,
604 const exploded_edge &eedge,
605 const event_loc_info &loc_info)
606 : superedge_event (kind, eedge, loc_info)
608 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
611 /* Implementation of diagnostic_event::get_meaning vfunc for
614 diagnostic_event::meaning
615 cfg_edge_event::get_meaning () const
617 const cfg_superedge& cfg_sedge = get_cfg_superedge ();
618 if (cfg_sedge.true_value_p ())
619 return meaning (VERB_branch, PROPERTY_true);
620 else if (cfg_sedge.false_value_p ())
621 return meaning (VERB_branch, PROPERTY_false);
626 /* class start_cfg_edge_event : public cfg_edge_event. */
628 /* Implementation of diagnostic_event::get_desc vfunc for
629 start_cfg_edge_event.
631 If -fanalyzer-verbose-edges, then generate low-level descriptions, such
633 "taking 'true' edge SN:7 -> SN:8".
635 Otherwise, generate strings using the label of the underlying CFG if
637 "following 'true' branch..." or
638 "following 'case 3' branch..."
639 "following 'default' branch..."
641 For conditionals, attempt to supply a description of the condition that
643 "following 'false' branch (when 'ptr' is non-NULL)..."
645 Failing that, return an empty description (which will lead to this event
649 start_cfg_edge_event::get_desc (bool can_colorize) const
651 bool user_facing = !flag_analyzer_verbose_edges;
652 label_text edge_desc (m_sedge->get_description (user_facing));
655 if (edge_desc.get () && strlen (edge_desc.get ()) > 0)
657 label_text cond_desc = maybe_describe_condition (can_colorize);
659 if (cond_desc.get ())
660 return make_label_text (can_colorize,
661 "following %qs branch (%s)...",
662 edge_desc.get (), cond_desc.get ());
664 return make_label_text (can_colorize,
665 "following %qs branch...",
669 return label_text::borrow ("");
673 if (strlen (edge_desc.get ()) > 0)
674 return make_label_text (can_colorize,
675 "taking %qs edge SN:%i -> SN:%i",
677 m_sedge->m_src->m_index,
678 m_sedge->m_dest->m_index);
680 return make_label_text (can_colorize,
681 "taking edge SN:%i -> SN:%i",
682 m_sedge->m_src->m_index,
683 m_sedge->m_dest->m_index);
687 /* Attempt to generate a description of any condition that holds at this edge.
689 The intent is to make the user-facing messages more clear, especially for
690 cases where there's a single or double-negative, such as
691 when describing the false branch of an inverted condition.
693 For example, rather than printing just:
698 | (1) following 'false' branch...
700 it's clearer to spell out the condition that holds:
705 | (1) following 'false' branch (when 'ptr' is non-NULL)...
706 ^^^^^^^^^^^^^^^^^^^^^^
708 In the above example, this function would generate the highlighted
709 string: "when 'ptr' is non-NULL".
711 If the edge is not a condition, or it's not clear that a description of
712 the condition would be helpful to the user, return NULL. */
715 start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const
717 const cfg_superedge& cfg_sedge = get_cfg_superedge ();
719 if (cfg_sedge.true_value_p () || cfg_sedge.false_value_p ())
721 const gimple *last_stmt = m_sedge->m_src->get_last_stmt ();
722 if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
724 enum tree_code op = gimple_cond_code (cond_stmt);
725 tree lhs = gimple_cond_lhs (cond_stmt);
726 tree rhs = gimple_cond_rhs (cond_stmt);
727 if (cfg_sedge.false_value_p ())
728 op = invert_tree_comparison (op, false /* honor_nans */);
729 return maybe_describe_condition (can_colorize,
733 return label_text::borrow (NULL);
736 /* Subroutine of maybe_describe_condition above.
738 Attempt to generate a user-facing description of the condition
739 LHS OP RHS, but only if it is likely to make it easier for the
740 user to understand a condition. */
743 start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
748 /* In theory we could just build a tree via
749 fold_build2 (op, boolean_type_node, lhs, rhs)
750 and print it with %qE on it, but this leads to warts such as
751 parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
753 /* Special-case: describe testing the result of strcmp, as figuring
754 out what the "true" or "false" path is can be confusing to the user. */
755 if (TREE_CODE (lhs) == SSA_NAME
758 if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
759 if (is_special_named_call_p (call, "strcmp", 2))
762 return label_text::borrow ("when the strings are equal");
764 return label_text::borrow ("when the strings are non-equal");
768 /* Only attempt to generate text for sufficiently simple expressions. */
769 if (!should_print_expr_p (lhs))
770 return label_text::borrow (NULL);
771 if (!should_print_expr_p (rhs))
772 return label_text::borrow (NULL);
774 /* Special cases for pointer comparisons against NULL. */
775 if (POINTER_TYPE_P (TREE_TYPE (lhs))
776 && POINTER_TYPE_P (TREE_TYPE (rhs))
780 return make_label_text (can_colorize, "when %qE is NULL",
783 return make_label_text (can_colorize, "when %qE is non-NULL",
787 return make_label_text (can_colorize, "when %<%E %s %E%>",
788 lhs, op_symbol_code (op), rhs);
791 /* Subroutine of maybe_describe_condition.
793 Return true if EXPR is we will get suitable user-facing output
797 start_cfg_edge_event::should_print_expr_p (tree expr)
799 if (TREE_CODE (expr) == SSA_NAME)
801 if (SSA_NAME_VAR (expr))
802 return should_print_expr_p (SSA_NAME_VAR (expr));
810 if (CONSTANT_CLASS_P (expr))
816 /* class call_event : public superedge_event. */
818 /* call_event's ctor. */
820 call_event::call_event (const exploded_edge &eedge,
821 const event_loc_info &loc_info)
822 : superedge_event (EK_CALL_EDGE, eedge, loc_info)
825 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
827 m_src_snode = eedge.m_src->get_supernode ();
828 m_dest_snode = eedge.m_dest->get_supernode ();
831 /* Implementation of diagnostic_event::get_desc vfunc for
834 If this call event passes critical state for an sm-based warning,
835 allow the diagnostic to generate a precise description, such as:
837 "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
839 Otherwise, generate a description of the form
840 "calling 'foo' from 'bar'". */
843 call_event::get_desc (bool can_colorize) const
845 if (m_critical_state && m_pending_diagnostic)
848 tree var = fixup_tree_for_diagnostic (m_var);
849 label_text custom_desc
850 = m_pending_diagnostic->describe_call_with_state
851 (evdesc::call_with_state (can_colorize,
852 m_src_snode->m_fun->decl,
853 m_dest_snode->m_fun->decl,
856 if (custom_desc.get ())
860 return make_label_text (can_colorize,
861 "calling %qE from %qE",
862 get_callee_fndecl (),
863 get_caller_fndecl ());
866 /* Implementation of diagnostic_event::get_meaning vfunc for
867 function call events. */
869 diagnostic_event::meaning
870 call_event::get_meaning () const
872 return meaning (VERB_call, NOUN_function);
875 /* Override of checker_event::is_call_p for calls. */
878 call_event::is_call_p () const
884 call_event::get_caller_fndecl () const
886 return m_src_snode->m_fun->decl;
890 call_event::get_callee_fndecl () const
892 return m_dest_snode->m_fun->decl;
895 /* class return_event : public superedge_event. */
897 /* return_event's ctor. */
899 return_event::return_event (const exploded_edge &eedge,
900 const event_loc_info &loc_info)
901 : superedge_event (EK_RETURN_EDGE, eedge, loc_info)
904 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
906 m_src_snode = eedge.m_src->get_supernode ();
907 m_dest_snode = eedge.m_dest->get_supernode ();
910 /* Implementation of diagnostic_event::get_desc vfunc for
913 If this return event returns critical state for an sm-based warning,
914 allow the diagnostic to generate a precise description, such as:
916 "possible of NULL to 'foo' from 'bar'"
918 Otherwise, generate a description of the form
919 "returning to 'foo' from 'bar'. */
922 return_event::get_desc (bool can_colorize) const
924 /* For greatest precision-of-wording, if this is returning the
925 state involved in the pending diagnostic, give the pending
926 diagnostic a chance to describe this return (in terms of
928 if (m_critical_state && m_pending_diagnostic)
930 label_text custom_desc
931 = m_pending_diagnostic->describe_return_of_state
932 (evdesc::return_of_state (can_colorize,
933 m_dest_snode->m_fun->decl,
934 m_src_snode->m_fun->decl,
936 if (custom_desc.get ())
939 return make_label_text (can_colorize,
940 "returning to %qE from %qE",
941 m_dest_snode->m_fun->decl,
942 m_src_snode->m_fun->decl);
945 /* Implementation of diagnostic_event::get_meaning vfunc for
946 function return events. */
948 diagnostic_event::meaning
949 return_event::get_meaning () const
951 return meaning (VERB_return, NOUN_function);
954 /* Override of checker_event::is_return_p for returns. */
957 return_event::is_return_p () const
962 /* class start_consolidated_cfg_edges_event : public checker_event. */
965 start_consolidated_cfg_edges_event::get_desc (bool can_colorize) const
967 return make_label_text (can_colorize,
968 "following %qs branch...",
969 m_edge_sense ? "true" : "false");
972 /* Implementation of diagnostic_event::get_meaning vfunc for
973 start_consolidated_cfg_edges_event. */
975 diagnostic_event::meaning
976 start_consolidated_cfg_edges_event::get_meaning () const
978 return meaning (VERB_branch,
979 (m_edge_sense ? PROPERTY_true : PROPERTY_false));
982 /* class inlined_call_event : public checker_event. */
985 inlined_call_event::get_desc (bool can_colorize) const
987 return make_label_text (can_colorize,
988 "inlined call to %qE from %qE",
989 m_apparent_callee_fndecl,
990 m_apparent_caller_fndecl);
993 /* Implementation of diagnostic_event::get_meaning vfunc for
994 reconstructed inlined function calls. */
996 diagnostic_event::meaning
997 inlined_call_event::get_meaning () const
999 return meaning (VERB_call, NOUN_function);
1002 /* class setjmp_event : public checker_event. */
1004 /* Implementation of diagnostic_event::get_desc vfunc for
1008 setjmp_event::get_desc (bool can_colorize) const
1010 return make_label_text (can_colorize,
1012 get_user_facing_name (m_setjmp_call));
1015 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1017 Record this setjmp's event ID into the path, so that rewind events can
1021 setjmp_event::prepare_for_emission (checker_path *path,
1022 pending_diagnostic *pd,
1023 diagnostic_event_id_t emission_id)
1025 checker_event::prepare_for_emission (path, pd, emission_id);
1026 path->record_setjmp_event (m_enode, emission_id);
1029 /* class rewind_event : public checker_event. */
1031 /* Get the fndecl containing the site of the longjmp call. */
1034 rewind_event::get_longjmp_caller () const
1036 return m_eedge->m_src->get_function ()->decl;
1039 /* Get the fndecl containing the site of the setjmp call. */
1042 rewind_event::get_setjmp_caller () const
1044 return m_eedge->m_dest->get_function ()->decl;
1047 /* rewind_event's ctor. */
1049 rewind_event::rewind_event (const exploded_edge *eedge,
1050 enum event_kind kind,
1051 const event_loc_info &loc_info,
1052 const rewind_info_t *rewind_info)
1053 : checker_event (kind, loc_info),
1054 m_rewind_info (rewind_info),
1057 gcc_assert (m_eedge->m_custom_info.get () == m_rewind_info);
1060 /* class rewind_from_longjmp_event : public rewind_event. */
1062 /* Implementation of diagnostic_event::get_desc vfunc for
1063 rewind_from_longjmp_event. */
1066 rewind_from_longjmp_event::get_desc (bool can_colorize) const
1068 const char *src_name
1069 = get_user_facing_name (m_rewind_info->get_longjmp_call ());
1071 if (get_longjmp_caller () == get_setjmp_caller ())
1072 /* Special-case: purely intraprocedural rewind. */
1073 return make_label_text (can_colorize,
1074 "rewinding within %qE from %qs...",
1075 get_longjmp_caller (),
1078 return make_label_text (can_colorize,
1079 "rewinding from %qs in %qE...",
1081 get_longjmp_caller ());
1084 /* class rewind_to_setjmp_event : public rewind_event. */
1086 /* Implementation of diagnostic_event::get_desc vfunc for
1087 rewind_to_setjmp_event. */
1090 rewind_to_setjmp_event::get_desc (bool can_colorize) const
1092 const char *dst_name
1093 = get_user_facing_name (m_rewind_info->get_setjmp_call ());
1095 /* If we can, identify the ID of the setjmp_event. */
1096 if (m_original_setjmp_event_id.known_p ())
1098 if (get_longjmp_caller () == get_setjmp_caller ())
1099 /* Special-case: purely intraprocedural rewind. */
1100 return make_label_text (can_colorize,
1101 "...to %qs (saved at %@)",
1103 &m_original_setjmp_event_id);
1105 return make_label_text (can_colorize,
1106 "...to %qs in %qE (saved at %@)",
1108 get_setjmp_caller (),
1109 &m_original_setjmp_event_id);
1113 if (get_longjmp_caller () == get_setjmp_caller ())
1114 /* Special-case: purely intraprocedural rewind. */
1115 return make_label_text (can_colorize,
1118 get_setjmp_caller ());
1120 return make_label_text (can_colorize,
1123 get_setjmp_caller ());
1127 /* Implementation of checker_event::prepare_for_emission vfunc for
1128 rewind_to_setjmp_event.
1130 Attempt to look up the setjmp event ID that recorded the jmp_buf
1134 rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
1135 pending_diagnostic *pd,
1136 diagnostic_event_id_t emission_id)
1138 checker_event::prepare_for_emission (path, pd, emission_id);
1139 path->get_setjmp_event (m_rewind_info->get_enode_origin (),
1140 &m_original_setjmp_event_id);
1143 /* class warning_event : public checker_event. */
1145 /* Implementation of diagnostic_event::get_desc vfunc for
1148 If the pending diagnostic implements describe_final_event, use it,
1149 generating a precise description e.g.
1150 "second 'free' here; first 'free' was at (7)"
1152 Otherwise generate a generic description. */
1155 warning_event::get_desc (bool can_colorize) const
1157 if (m_pending_diagnostic)
1159 tree var = fixup_tree_for_diagnostic (m_var);
1161 = m_pending_diagnostic->describe_final_event
1162 (evdesc::final_event (can_colorize, var, m_state));
1165 if (m_sm && flag_analyzer_verbose_state_changes)
1168 return make_label_text (can_colorize,
1169 "%s (%qE is in state %qs)",
1171 var, m_state->get_name ());
1173 return make_label_text (can_colorize,
1174 "%s (in global state %qs)",
1176 m_state->get_name ());
1186 return make_label_text (can_colorize,
1187 "here (%qE is in state %qs)",
1188 m_var, m_state->get_name ());
1190 return make_label_text (can_colorize,
1191 "here (in global state %qs)",
1192 m_state->get_name ());
1195 return label_text::borrow ("here");
1198 /* Implementation of diagnostic_event::get_meaning vfunc for
1201 diagnostic_event::meaning
1202 warning_event::get_meaning () const
1204 return meaning (VERB_danger, NOUN_unknown);
1209 #endif /* #if ENABLE_ANALYZER */