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 location_t loc, tree fndecl, int depth)
155 : m_kind (kind), m_loc (loc),
156 m_original_fndecl (fndecl), m_effective_fndecl (fndecl),
157 m_original_depth (depth), m_effective_depth (depth),
158 m_pending_diagnostic (NULL), m_emission_id (),
159 m_logical_loc (fndecl)
161 /* Update effective fndecl and depth if inlining has been recorded. */
162 if (flag_analyzer_undo_inlining)
164 inlining_info info (loc);
165 if (info.get_inner_fndecl ())
167 m_effective_fndecl = info.get_inner_fndecl ();
168 m_effective_depth += info.get_extra_frames ();
169 m_logical_loc = tree_logical_location (m_effective_fndecl);
174 /* No-op implementation of diagnostic_event::get_meaning vfunc for
175 checker_event: checker events have no meaning by default. */
177 diagnostic_event::meaning
178 checker_event::get_meaning () const
183 /* Dump this event to PP (for debugging/logging purposes). */
186 checker_event::dump (pretty_printer *pp) const
188 label_text event_desc (get_desc (false));
189 pp_printf (pp, "\"%s\" (depth %i",
190 event_desc.get (), m_effective_depth);
192 if (m_effective_depth != m_original_depth)
193 pp_printf (pp, " corrected from %i",
195 if (m_effective_fndecl)
197 pp_printf (pp, ", fndecl %qE", m_effective_fndecl);
198 if (m_effective_fndecl != m_original_fndecl)
199 pp_printf (pp, " corrected from %qE", m_original_fndecl);
201 pp_printf (pp, ", m_loc=%x)",
205 /* Dump this event to stderr (for debugging/logging purposes). */
208 checker_event::debug () const
211 pp_format_decoder (&pp) = default_tree_printer;
212 pp_show_color (&pp) = pp_show_color (global_dc->printer);
213 pp.buffer->stream = stderr;
219 /* Hook for being notified when this event has its final id EMISSION_ID
220 and is about to emitted for PD.
222 Base implementation of checker_event::prepare_for_emission vfunc;
223 subclasses that override this should chain up to it.
225 Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
226 side-effects of the call to get_desc take place before
227 pending_diagnostic::emit is called.
229 For example, state_change_event::get_desc can call
230 pending_diagnostic::describe_state_change; free_of_non_heap can use this
231 to tweak the message (TODO: would be neater to simply capture the
232 pertinent data within the sm-state). */
235 checker_event::prepare_for_emission (checker_path *,
236 pending_diagnostic *pd,
237 diagnostic_event_id_t emission_id)
239 m_pending_diagnostic = pd;
240 m_emission_id = emission_id;
242 label_text desc = get_desc (false);
245 /* class debug_event : public checker_event. */
247 /* Implementation of diagnostic_event::get_desc vfunc for
249 Use the saved string as the event's description. */
252 debug_event::get_desc (bool) const
254 return label_text::borrow (m_desc);
257 /* class precanned_custom_event : public custom_event. */
259 /* Implementation of diagnostic_event::get_desc vfunc for
260 precanned_custom_event.
261 Use the saved string as the event's description. */
264 precanned_custom_event::get_desc (bool) const
266 return label_text::borrow (m_desc);
269 /* class statement_event : public checker_event. */
271 /* statement_event's ctor. */
273 statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
274 const program_state &dst_state)
275 : checker_event (EK_STMT, gimple_location (stmt), fndecl, depth),
277 m_dst_state (dst_state)
281 /* Implementation of diagnostic_event::get_desc vfunc for
283 Use the statement's dump form as the event's description. */
286 statement_event::get_desc (bool) const
289 pp_string (&pp, "stmt: ");
290 pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
291 return label_text::take (xstrdup (pp_formatted_text (&pp)));
294 /* class region_creation_event : public checker_event. */
296 region_creation_event::region_creation_event (location_t loc,
299 : checker_event (EK_REGION_CREATION, loc, fndecl, depth)
303 /* The various region_creation_event subclasses' get_desc
307 region_creation_event_memory_space::get_desc (bool) const
312 return label_text::borrow ("region created here");
314 return label_text::borrow ("region created on stack here");
316 return label_text::borrow ("region created on heap here");
321 region_creation_event_capacity::get_desc (bool can_colorize) const
323 gcc_assert (m_capacity);
324 if (TREE_CODE (m_capacity) == INTEGER_CST)
326 unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
327 return make_label_text_n (can_colorize,
329 "capacity: %wu byte",
330 "capacity: %wu bytes",
334 return make_label_text (can_colorize,
335 "capacity: %qE bytes", m_capacity);
339 region_creation_event_allocation_size::get_desc (bool can_colorize) const
343 if (TREE_CODE (m_capacity) == INTEGER_CST)
344 return make_label_text_n (can_colorize,
345 tree_to_uhwi (m_capacity),
346 "allocated %E byte here",
347 "allocated %E bytes here",
350 return make_label_text (can_colorize,
351 "allocated %qE bytes here",
354 return make_label_text (can_colorize, "allocated here");
358 region_creation_event_debug::get_desc (bool) const
361 pp_format_decoder (&pp) = default_tree_printer;
362 pp_string (&pp, "region creation: ");
363 m_reg->dump_to_pp (&pp, true);
365 pp_printf (&pp, " capacity: %qE", m_capacity);
366 return label_text::take (xstrdup (pp_formatted_text (&pp)));
369 /* class function_entry_event : public checker_event. */
371 function_entry_event::function_entry_event (const program_point &dst_point)
372 : checker_event (EK_FUNCTION_ENTRY,
373 dst_point.get_supernode ()->get_start_location (),
374 dst_point.get_fndecl (),
375 dst_point.get_stack_depth ())
379 /* Implementation of diagnostic_event::get_desc vfunc for
380 function_entry_event.
382 Use a string such as "entry to 'foo'" as the event's description. */
385 function_entry_event::get_desc (bool can_colorize) const
387 return make_label_text (can_colorize, "entry to %qE", m_effective_fndecl);
390 /* Implementation of diagnostic_event::get_meaning vfunc for
393 diagnostic_event::meaning
394 function_entry_event::get_meaning () const
396 return meaning (VERB_enter, NOUN_function);
399 /* class state_change_event : public checker_event. */
401 /* state_change_event's ctor. */
403 state_change_event::state_change_event (const supernode *node,
406 const state_machine &sm,
408 state_machine::state_t from,
409 state_machine::state_t to,
410 const svalue *origin,
411 const program_state &dst_state)
412 : checker_event (EK_STATE_CHANGE,
413 stmt->location, node->m_fun->decl,
415 m_node (node), m_stmt (stmt), m_sm (sm),
416 m_sval (sval), m_from (from), m_to (to),
418 m_dst_state (dst_state)
422 /* Implementation of diagnostic_event::get_desc vfunc for
425 Attempt to generate a nicer human-readable description.
426 For greatest precision-of-wording, give the pending diagnostic
427 a chance to describe this state change (in terms of the
429 Note that we only have a pending_diagnostic set on the event once
430 the diagnostic is about to being emitted, so the description for
431 an event can change. */
434 state_change_event::get_desc (bool can_colorize) const
436 if (m_pending_diagnostic)
438 region_model *model = m_dst_state.m_region_model;
439 tree var = model->get_representative_tree (m_sval);
440 tree origin = model->get_representative_tree (m_origin);
441 label_text custom_desc
442 = m_pending_diagnostic->describe_state_change
443 (evdesc::state_change (can_colorize, var, origin,
444 m_from, m_to, m_emission_id, *this));
445 if (custom_desc.get ())
447 if (flag_analyzer_verbose_state_changes)
449 /* Get any "meaning" of event. */
450 diagnostic_event::meaning meaning = get_meaning ();
451 pretty_printer meaning_pp;
452 meaning.dump_to_pp (&meaning_pp);
454 /* Append debug version. */
456 return make_label_text
458 "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
464 pp_formatted_text (&meaning_pp));
466 return make_label_text
468 "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
473 pp_formatted_text (&meaning_pp));
480 /* Fallback description. */
483 label_text sval_desc = m_sval->get_desc ();
486 label_text origin_desc = m_origin->get_desc ();
487 return make_label_text
489 "state of %qs: %qs -> %qs (origin: %qs)",
496 return make_label_text
498 "state of %qs: %qs -> %qs (NULL origin)",
505 gcc_assert (m_origin == NULL);
506 return make_label_text
508 "global state: %qs -> %qs",
514 /* Implementation of diagnostic_event::get_meaning vfunc for
515 state change events: delegate to the pending_diagnostic to
518 diagnostic_event::meaning
519 state_change_event::get_meaning () const
521 if (m_pending_diagnostic)
523 region_model *model = m_dst_state.m_region_model;
524 tree var = model->get_representative_tree (m_sval);
525 tree origin = model->get_representative_tree (m_origin);
526 return m_pending_diagnostic->get_meaning_for_state_change
527 (evdesc::state_change (false, var, origin,
528 m_from, m_to, m_emission_id, *this));
534 /* class superedge_event : public checker_event. */
536 /* Get the callgraph_superedge for this superedge_event, which must be
537 for an interprocedural edge, rather than a CFG edge. */
539 const callgraph_superedge&
540 superedge_event::get_callgraph_superedge () const
542 gcc_assert (m_sedge->m_kind != SUPEREDGE_CFG_EDGE);
543 return *m_sedge->dyn_cast_callgraph_superedge ();
546 /* Determine if this event should be filtered at the given verbosity
550 superedge_event::should_filter_p (int verbosity) const
552 switch (m_sedge->m_kind)
554 case SUPEREDGE_CFG_EDGE:
561 /* Filter events with empty descriptions. This ought to filter
562 FALLTHRU, but retain true/false/switch edges. */
563 label_text desc = get_desc (false);
564 gcc_assert (desc.get ());
565 if (desc.get ()[0] == '\0')
577 /* superedge_event's ctor. */
579 superedge_event::superedge_event (enum event_kind kind,
580 const exploded_edge &eedge,
581 location_t loc, tree fndecl, int depth)
582 : checker_event (kind, loc, fndecl, depth),
583 m_eedge (eedge), m_sedge (eedge.m_sedge),
584 m_var (NULL_TREE), m_critical_state (0)
588 /* class cfg_edge_event : public superedge_event. */
590 /* Get the cfg_superedge for this cfg_edge_event. */
592 const cfg_superedge &
593 cfg_edge_event::get_cfg_superedge () const
595 return *m_sedge->dyn_cast_cfg_superedge ();
598 /* cfg_edge_event's ctor. */
600 cfg_edge_event::cfg_edge_event (enum event_kind kind,
601 const exploded_edge &eedge,
602 location_t loc, tree fndecl, int depth)
603 : superedge_event (kind, eedge, loc, fndecl, depth)
605 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
608 /* Implementation of diagnostic_event::get_meaning vfunc for
611 diagnostic_event::meaning
612 cfg_edge_event::get_meaning () const
614 const cfg_superedge& cfg_sedge = get_cfg_superedge ();
615 if (cfg_sedge.true_value_p ())
616 return meaning (VERB_branch, PROPERTY_true);
617 else if (cfg_sedge.false_value_p ())
618 return meaning (VERB_branch, PROPERTY_false);
623 /* class start_cfg_edge_event : public cfg_edge_event. */
625 /* Implementation of diagnostic_event::get_desc vfunc for
626 start_cfg_edge_event.
628 If -fanalyzer-verbose-edges, then generate low-level descriptions, such
630 "taking 'true' edge SN:7 -> SN:8".
632 Otherwise, generate strings using the label of the underlying CFG if
634 "following 'true' branch..." or
635 "following 'case 3' branch..."
636 "following 'default' branch..."
638 For conditionals, attempt to supply a description of the condition that
640 "following 'false' branch (when 'ptr' is non-NULL)..."
642 Failing that, return an empty description (which will lead to this event
646 start_cfg_edge_event::get_desc (bool can_colorize) const
648 bool user_facing = !flag_analyzer_verbose_edges;
649 label_text edge_desc (m_sedge->get_description (user_facing));
652 if (edge_desc.get () && strlen (edge_desc.get ()) > 0)
654 label_text cond_desc = maybe_describe_condition (can_colorize);
656 if (cond_desc.get ())
657 return make_label_text (can_colorize,
658 "following %qs branch (%s)...",
659 edge_desc.get (), cond_desc.get ());
661 return make_label_text (can_colorize,
662 "following %qs branch...",
666 return label_text::borrow ("");
670 if (strlen (edge_desc.get ()) > 0)
671 return make_label_text (can_colorize,
672 "taking %qs edge SN:%i -> SN:%i",
674 m_sedge->m_src->m_index,
675 m_sedge->m_dest->m_index);
677 return make_label_text (can_colorize,
678 "taking edge SN:%i -> SN:%i",
679 m_sedge->m_src->m_index,
680 m_sedge->m_dest->m_index);
684 /* Attempt to generate a description of any condition that holds at this edge.
686 The intent is to make the user-facing messages more clear, especially for
687 cases where there's a single or double-negative, such as
688 when describing the false branch of an inverted condition.
690 For example, rather than printing just:
695 | (1) following 'false' branch...
697 it's clearer to spell out the condition that holds:
702 | (1) following 'false' branch (when 'ptr' is non-NULL)...
703 ^^^^^^^^^^^^^^^^^^^^^^
705 In the above example, this function would generate the highlighted
706 string: "when 'ptr' is non-NULL".
708 If the edge is not a condition, or it's not clear that a description of
709 the condition would be helpful to the user, return NULL. */
712 start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const
714 const cfg_superedge& cfg_sedge = get_cfg_superedge ();
716 if (cfg_sedge.true_value_p () || cfg_sedge.false_value_p ())
718 const gimple *last_stmt = m_sedge->m_src->get_last_stmt ();
719 if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
721 enum tree_code op = gimple_cond_code (cond_stmt);
722 tree lhs = gimple_cond_lhs (cond_stmt);
723 tree rhs = gimple_cond_rhs (cond_stmt);
724 if (cfg_sedge.false_value_p ())
725 op = invert_tree_comparison (op, false /* honor_nans */);
726 return maybe_describe_condition (can_colorize,
730 return label_text::borrow (NULL);
733 /* Subroutine of maybe_describe_condition above.
735 Attempt to generate a user-facing description of the condition
736 LHS OP RHS, but only if it is likely to make it easier for the
737 user to understand a condition. */
740 start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
745 /* In theory we could just build a tree via
746 fold_build2 (op, boolean_type_node, lhs, rhs)
747 and print it with %qE on it, but this leads to warts such as
748 parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
750 /* Special-case: describe testing the result of strcmp, as figuring
751 out what the "true" or "false" path is can be confusing to the user. */
752 if (TREE_CODE (lhs) == SSA_NAME
755 if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
756 if (is_special_named_call_p (call, "strcmp", 2))
759 return label_text::borrow ("when the strings are equal");
761 return label_text::borrow ("when the strings are non-equal");
765 /* Only attempt to generate text for sufficiently simple expressions. */
766 if (!should_print_expr_p (lhs))
767 return label_text::borrow (NULL);
768 if (!should_print_expr_p (rhs))
769 return label_text::borrow (NULL);
771 /* Special cases for pointer comparisons against NULL. */
772 if (POINTER_TYPE_P (TREE_TYPE (lhs))
773 && POINTER_TYPE_P (TREE_TYPE (rhs))
777 return make_label_text (can_colorize, "when %qE is NULL",
780 return make_label_text (can_colorize, "when %qE is non-NULL",
784 return make_label_text (can_colorize, "when %<%E %s %E%>",
785 lhs, op_symbol_code (op), rhs);
788 /* Subroutine of maybe_describe_condition.
790 Return true if EXPR is we will get suitable user-facing output
794 start_cfg_edge_event::should_print_expr_p (tree expr)
796 if (TREE_CODE (expr) == SSA_NAME)
798 if (SSA_NAME_VAR (expr))
799 return should_print_expr_p (SSA_NAME_VAR (expr));
807 if (CONSTANT_CLASS_P (expr))
813 /* class call_event : public superedge_event. */
815 /* call_event's ctor. */
817 call_event::call_event (const exploded_edge &eedge,
818 location_t loc, tree fndecl, int depth)
819 : superedge_event (EK_CALL_EDGE, eedge, loc, fndecl, depth)
822 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
824 m_src_snode = eedge.m_src->get_supernode ();
825 m_dest_snode = eedge.m_dest->get_supernode ();
828 /* Implementation of diagnostic_event::get_desc vfunc for
831 If this call event passes critical state for an sm-based warning,
832 allow the diagnostic to generate a precise description, such as:
834 "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
836 Otherwise, generate a description of the form
837 "calling 'foo' from 'bar'". */
840 call_event::get_desc (bool can_colorize) const
842 if (m_critical_state && m_pending_diagnostic)
845 tree var = fixup_tree_for_diagnostic (m_var);
846 label_text custom_desc
847 = m_pending_diagnostic->describe_call_with_state
848 (evdesc::call_with_state (can_colorize,
849 m_src_snode->m_fun->decl,
850 m_dest_snode->m_fun->decl,
853 if (custom_desc.get ())
857 return make_label_text (can_colorize,
858 "calling %qE from %qE",
859 get_callee_fndecl (),
860 get_caller_fndecl ());
863 /* Implementation of diagnostic_event::get_meaning vfunc for
864 function call events. */
866 diagnostic_event::meaning
867 call_event::get_meaning () const
869 return meaning (VERB_call, NOUN_function);
872 /* Override of checker_event::is_call_p for calls. */
875 call_event::is_call_p () const
881 call_event::get_caller_fndecl () const
883 return m_src_snode->m_fun->decl;
887 call_event::get_callee_fndecl () const
889 return m_dest_snode->m_fun->decl;
892 /* class return_event : public superedge_event. */
894 /* return_event's ctor. */
896 return_event::return_event (const exploded_edge &eedge,
897 location_t loc, tree fndecl, int depth)
898 : superedge_event (EK_RETURN_EDGE, eedge, loc, fndecl, depth)
901 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
903 m_src_snode = eedge.m_src->get_supernode ();
904 m_dest_snode = eedge.m_dest->get_supernode ();
907 /* Implementation of diagnostic_event::get_desc vfunc for
910 If this return event returns critical state for an sm-based warning,
911 allow the diagnostic to generate a precise description, such as:
913 "possible of NULL to 'foo' from 'bar'"
915 Otherwise, generate a description of the form
916 "returning to 'foo' from 'bar'. */
919 return_event::get_desc (bool can_colorize) const
921 /* For greatest precision-of-wording, if this is returning the
922 state involved in the pending diagnostic, give the pending
923 diagnostic a chance to describe this return (in terms of
925 if (m_critical_state && m_pending_diagnostic)
927 label_text custom_desc
928 = m_pending_diagnostic->describe_return_of_state
929 (evdesc::return_of_state (can_colorize,
930 m_dest_snode->m_fun->decl,
931 m_src_snode->m_fun->decl,
933 if (custom_desc.get ())
936 return make_label_text (can_colorize,
937 "returning to %qE from %qE",
938 m_dest_snode->m_fun->decl,
939 m_src_snode->m_fun->decl);
942 /* Implementation of diagnostic_event::get_meaning vfunc for
943 function return events. */
945 diagnostic_event::meaning
946 return_event::get_meaning () const
948 return meaning (VERB_return, NOUN_function);
951 /* Override of checker_event::is_return_p for returns. */
954 return_event::is_return_p () const
959 /* class start_consolidated_cfg_edges_event : public checker_event. */
962 start_consolidated_cfg_edges_event::get_desc (bool can_colorize) const
964 return make_label_text (can_colorize,
965 "following %qs branch...",
966 m_edge_sense ? "true" : "false");
969 /* Implementation of diagnostic_event::get_meaning vfunc for
970 start_consolidated_cfg_edges_event. */
972 diagnostic_event::meaning
973 start_consolidated_cfg_edges_event::get_meaning () const
975 return meaning (VERB_branch,
976 (m_edge_sense ? PROPERTY_true : PROPERTY_false));
979 /* class inlined_call_event : public checker_event. */
982 inlined_call_event::get_desc (bool can_colorize) const
984 return make_label_text (can_colorize,
985 "inlined call to %qE from %qE",
986 m_apparent_callee_fndecl,
987 m_apparent_caller_fndecl);
990 /* Implementation of diagnostic_event::get_meaning vfunc for
991 reconstructed inlined function calls. */
993 diagnostic_event::meaning
994 inlined_call_event::get_meaning () const
996 return meaning (VERB_call, NOUN_function);
999 /* class setjmp_event : public checker_event. */
1001 /* Implementation of diagnostic_event::get_desc vfunc for
1005 setjmp_event::get_desc (bool can_colorize) const
1007 return make_label_text (can_colorize,
1009 get_user_facing_name (m_setjmp_call));
1012 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1014 Record this setjmp's event ID into the path, so that rewind events can
1018 setjmp_event::prepare_for_emission (checker_path *path,
1019 pending_diagnostic *pd,
1020 diagnostic_event_id_t emission_id)
1022 checker_event::prepare_for_emission (path, pd, emission_id);
1023 path->record_setjmp_event (m_enode, emission_id);
1026 /* class rewind_event : public checker_event. */
1028 /* Get the fndecl containing the site of the longjmp call. */
1031 rewind_event::get_longjmp_caller () const
1033 return m_eedge->m_src->get_function ()->decl;
1036 /* Get the fndecl containing the site of the setjmp call. */
1039 rewind_event::get_setjmp_caller () const
1041 return m_eedge->m_dest->get_function ()->decl;
1044 /* rewind_event's ctor. */
1046 rewind_event::rewind_event (const exploded_edge *eedge,
1047 enum event_kind kind,
1048 location_t loc, tree fndecl, int depth,
1049 const rewind_info_t *rewind_info)
1050 : checker_event (kind, loc, fndecl, depth),
1051 m_rewind_info (rewind_info),
1054 gcc_assert (m_eedge->m_custom_info.get () == m_rewind_info);
1057 /* class rewind_from_longjmp_event : public rewind_event. */
1059 /* Implementation of diagnostic_event::get_desc vfunc for
1060 rewind_from_longjmp_event. */
1063 rewind_from_longjmp_event::get_desc (bool can_colorize) const
1065 const char *src_name
1066 = get_user_facing_name (m_rewind_info->get_longjmp_call ());
1068 if (get_longjmp_caller () == get_setjmp_caller ())
1069 /* Special-case: purely intraprocedural rewind. */
1070 return make_label_text (can_colorize,
1071 "rewinding within %qE from %qs...",
1072 get_longjmp_caller (),
1075 return make_label_text (can_colorize,
1076 "rewinding from %qs in %qE...",
1078 get_longjmp_caller ());
1081 /* class rewind_to_setjmp_event : public rewind_event. */
1083 /* Implementation of diagnostic_event::get_desc vfunc for
1084 rewind_to_setjmp_event. */
1087 rewind_to_setjmp_event::get_desc (bool can_colorize) const
1089 const char *dst_name
1090 = get_user_facing_name (m_rewind_info->get_setjmp_call ());
1092 /* If we can, identify the ID of the setjmp_event. */
1093 if (m_original_setjmp_event_id.known_p ())
1095 if (get_longjmp_caller () == get_setjmp_caller ())
1096 /* Special-case: purely intraprocedural rewind. */
1097 return make_label_text (can_colorize,
1098 "...to %qs (saved at %@)",
1100 &m_original_setjmp_event_id);
1102 return make_label_text (can_colorize,
1103 "...to %qs in %qE (saved at %@)",
1105 get_setjmp_caller (),
1106 &m_original_setjmp_event_id);
1110 if (get_longjmp_caller () == get_setjmp_caller ())
1111 /* Special-case: purely intraprocedural rewind. */
1112 return make_label_text (can_colorize,
1115 get_setjmp_caller ());
1117 return make_label_text (can_colorize,
1120 get_setjmp_caller ());
1124 /* Implementation of checker_event::prepare_for_emission vfunc for
1125 rewind_to_setjmp_event.
1127 Attempt to look up the setjmp event ID that recorded the jmp_buf
1131 rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
1132 pending_diagnostic *pd,
1133 diagnostic_event_id_t emission_id)
1135 checker_event::prepare_for_emission (path, pd, emission_id);
1136 path->get_setjmp_event (m_rewind_info->get_enode_origin (),
1137 &m_original_setjmp_event_id);
1140 /* class warning_event : public checker_event. */
1142 /* Implementation of diagnostic_event::get_desc vfunc for
1145 If the pending diagnostic implements describe_final_event, use it,
1146 generating a precise description e.g.
1147 "second 'free' here; first 'free' was at (7)"
1149 Otherwise generate a generic description. */
1152 warning_event::get_desc (bool can_colorize) const
1154 if (m_pending_diagnostic)
1156 tree var = fixup_tree_for_diagnostic (m_var);
1158 = m_pending_diagnostic->describe_final_event
1159 (evdesc::final_event (can_colorize, var, m_state));
1162 if (m_sm && flag_analyzer_verbose_state_changes)
1165 return make_label_text (can_colorize,
1166 "%s (%qE is in state %qs)",
1168 var, m_state->get_name ());
1170 return make_label_text (can_colorize,
1171 "%s (in global state %qs)",
1173 m_state->get_name ());
1183 return make_label_text (can_colorize,
1184 "here (%qE is in state %qs)",
1185 m_var, m_state->get_name ());
1187 return make_label_text (can_colorize,
1188 "here (in global state %qs)",
1189 m_state->get_name ());
1192 return label_text::borrow ("here");
1195 /* Implementation of diagnostic_event::get_meaning vfunc for
1198 diagnostic_event::meaning
1199 warning_event::get_meaning () const
1201 return meaning (VERB_danger, NOUN_unknown);
1206 #endif /* #if ENABLE_ANALYZER */