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)
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"
58 #include "diagnostic-format-sarif.h"
59 #include "tree-logical-location.h"
65 /* Get a string for EK. */
68 event_kind_to_string (enum event_kind ek
)
80 case EK_REGION_CREATION
:
81 return "EK_REGION_CREATION";
82 case EK_FUNCTION_ENTRY
:
83 return "EK_FUNCTION_ENTRY";
85 return "EK_STATE_CHANGE";
86 case EK_START_CFG_EDGE
:
87 return "EK_START_CFG_EDGE";
89 return "EK_END_CFG_EDGE";
91 return "EK_CALL_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";
99 return "EK_INLINED_CALL";
102 case EK_REWIND_FROM_LONGJMP
:
103 return "EK_REWIND_FROM_LONGJMP";
104 case EK_REWIND_TO_SETJMP
:
105 return "EK_REWIND_TO_SETJMP";
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
147 /* Implementation of diagnostic_event::maybe_add_sarif_properties
148 for 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). */
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",
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)",
193 /* Dump this event to stderr (for debugging/logging purposes). */
196 checker_event::debug () const
199 pp_format_decoder (&pp
) = default_tree_printer
;
200 pp_show_color (&pp
) = pp_show_color (global_dc
->printer
);
201 pp
.buffer
->stream
= stderr
;
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). */
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
237 Use the saved string as the event's description. */
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. */
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
)),
266 m_dst_state (dst_state
)
270 /* Implementation of diagnostic_event::get_desc vfunc for
272 Use the statement's dump form as the event's description. */
275 statement_event::get_desc (bool) const
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
294 region_creation_event_memory_space::get_desc (bool) const
299 return label_text::borrow ("region created here");
301 return label_text::borrow ("region created on stack here");
303 return label_text::borrow ("region created on heap here");
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
,
316 "capacity: %wu byte",
317 "capacity: %wu bytes",
321 return make_label_text (can_colorize
,
322 "capacity: %qE bytes", m_capacity
);
326 region_creation_event_allocation_size::get_desc (bool can_colorize
) const
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",
337 return make_label_text (can_colorize
,
338 "allocated %qE bytes here",
341 return make_label_text (can_colorize
, "allocated here");
345 region_creation_event_debug::get_desc (bool) const
348 pp_format_decoder (&pp
) = default_tree_printer
;
349 pp_string (&pp
, "region creation: ");
350 m_reg
->dump_to_pp (&pp
, true);
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. */
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
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
,
394 const state_machine
&sm
,
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
,
405 m_node (node
), m_stmt (stmt
), m_sm (sm
),
406 m_sval (sval
), m_from (from
), m_to (to
),
408 m_dst_state (dst_state
),
413 /* Implementation of diagnostic_event::get_desc vfunc for
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
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. */
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. */
447 return make_label_text
449 "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
455 pp_formatted_text (&meaning_pp
));
457 return make_label_text
459 "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
464 pp_formatted_text (&meaning_pp
));
471 /* Fallback description. */
474 label_text sval_desc
= m_sval
->get_desc ();
477 label_text origin_desc
= m_origin
->get_desc ();
478 return make_label_text
480 "state of %qs: %qs -> %qs (origin: %qs)",
487 return make_label_text
489 "state of %qs: %qs -> %qs (NULL origin)",
496 gcc_assert (m_origin
== NULL
);
497 return make_label_text
499 "global state: %qs -> %qs",
505 /* Implementation of diagnostic_event::get_meaning vfunc for
506 state change events: delegate to the pending_diagnostic to
509 diagnostic_event::meaning
510 state_change_event::get_meaning () const
512 if (m_pending_diagnostic
)
514 region_model
*model
= m_dst_state
.m_region_model
;
515 tree var
= model
->get_representative_tree (m_sval
);
516 tree origin
= model
->get_representative_tree (m_origin
);
517 return m_pending_diagnostic
->get_meaning_for_state_change
518 (evdesc::state_change (false, var
, origin
,
519 m_from
, m_to
, m_emission_id
, *this));
525 /* class superedge_event : public checker_event. */
527 /* Implementation of diagnostic_event::maybe_add_sarif_properties
528 for superedge_event. */
531 superedge_event::maybe_add_sarif_properties (sarif_object
&thread_flow_loc_obj
)
534 checker_event::maybe_add_sarif_properties (thread_flow_loc_obj
);
535 sarif_property_bag
&props
= thread_flow_loc_obj
.get_or_create_properties ();
536 #define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
538 props
.set (PROPERTY_PREFIX
"superedge", m_sedge
->to_json ());
539 #undef PROPERTY_PREFIX
542 /* Get the callgraph_superedge for this superedge_event, which must be
543 for an interprocedural edge, rather than a CFG edge. */
545 const callgraph_superedge
&
546 superedge_event::get_callgraph_superedge () const
548 gcc_assert (m_sedge
->m_kind
!= SUPEREDGE_CFG_EDGE
);
549 return *m_sedge
->dyn_cast_callgraph_superedge ();
552 /* Determine if this event should be filtered at the given verbosity
556 superedge_event::should_filter_p (int verbosity
) const
558 switch (m_sedge
->m_kind
)
560 case SUPEREDGE_CFG_EDGE
:
567 /* Filter events with empty descriptions. This ought to filter
568 FALLTHRU, but retain true/false/switch edges. */
569 label_text desc
= get_desc (false);
570 gcc_assert (desc
.get ());
571 if (desc
.get ()[0] == '\0')
583 /* superedge_event's ctor. */
585 superedge_event::superedge_event (enum event_kind kind
,
586 const exploded_edge
&eedge
,
587 const event_loc_info
&loc_info
)
588 : checker_event (kind
, loc_info
),
589 m_eedge (eedge
), m_sedge (eedge
.m_sedge
),
590 m_var (NULL_TREE
), m_critical_state (0)
592 /* Note that m_sedge can be nullptr for e.g. jumps through
593 function pointers. */
596 /* class cfg_edge_event : public superedge_event. */
598 /* Get the cfg_superedge for this cfg_edge_event. */
600 const cfg_superedge
&
601 cfg_edge_event::get_cfg_superedge () const
603 return *m_sedge
->dyn_cast_cfg_superedge ();
606 /* cfg_edge_event's ctor. */
608 cfg_edge_event::cfg_edge_event (enum event_kind kind
,
609 const exploded_edge
&eedge
,
610 const event_loc_info
&loc_info
)
611 : superedge_event (kind
, eedge
, loc_info
)
613 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_CFG_EDGE
);
616 /* Implementation of diagnostic_event::get_meaning vfunc for
619 diagnostic_event::meaning
620 cfg_edge_event::get_meaning () const
622 const cfg_superedge
& cfg_sedge
= get_cfg_superedge ();
623 if (cfg_sedge
.true_value_p ())
624 return meaning (VERB_branch
, PROPERTY_true
);
625 else if (cfg_sedge
.false_value_p ())
626 return meaning (VERB_branch
, PROPERTY_false
);
631 /* class start_cfg_edge_event : public cfg_edge_event. */
633 /* Implementation of diagnostic_event::get_desc vfunc for
634 start_cfg_edge_event.
636 If -fanalyzer-verbose-edges, then generate low-level descriptions, such
638 "taking 'true' edge SN:7 -> SN:8".
640 Otherwise, generate strings using the label of the underlying CFG if
642 "following 'true' branch..." or
643 "following 'case 3' branch..."
644 "following 'default' branch..."
646 For conditionals, attempt to supply a description of the condition that
648 "following 'false' branch (when 'ptr' is non-NULL)..."
650 Failing that, return an empty description (which will lead to this event
654 start_cfg_edge_event::get_desc (bool can_colorize
) const
656 bool user_facing
= !flag_analyzer_verbose_edges
;
657 label_text
edge_desc (m_sedge
->get_description (user_facing
));
660 if (edge_desc
.get () && strlen (edge_desc
.get ()) > 0)
662 label_text cond_desc
= maybe_describe_condition (can_colorize
);
664 if (cond_desc
.get ())
665 return make_label_text (can_colorize
,
666 "following %qs branch (%s)...",
667 edge_desc
.get (), cond_desc
.get ());
669 return make_label_text (can_colorize
,
670 "following %qs branch...",
674 return label_text::borrow ("");
678 if (strlen (edge_desc
.get ()) > 0)
679 return make_label_text (can_colorize
,
680 "taking %qs edge SN:%i -> SN:%i",
682 m_sedge
->m_src
->m_index
,
683 m_sedge
->m_dest
->m_index
);
685 return make_label_text (can_colorize
,
686 "taking edge SN:%i -> SN:%i",
687 m_sedge
->m_src
->m_index
,
688 m_sedge
->m_dest
->m_index
);
692 /* Attempt to generate a description of any condition that holds at this edge.
694 The intent is to make the user-facing messages more clear, especially for
695 cases where there's a single or double-negative, such as
696 when describing the false branch of an inverted condition.
698 For example, rather than printing just:
703 | (1) following 'false' branch...
705 it's clearer to spell out the condition that holds:
710 | (1) following 'false' branch (when 'ptr' is non-NULL)...
711 ^^^^^^^^^^^^^^^^^^^^^^
713 In the above example, this function would generate the highlighted
714 string: "when 'ptr' is non-NULL".
716 If the edge is not a condition, or it's not clear that a description of
717 the condition would be helpful to the user, return NULL. */
720 start_cfg_edge_event::maybe_describe_condition (bool can_colorize
) const
722 const cfg_superedge
& cfg_sedge
= get_cfg_superedge ();
724 if (cfg_sedge
.true_value_p () || cfg_sedge
.false_value_p ())
726 const gimple
*last_stmt
= m_sedge
->m_src
->get_last_stmt ();
727 if (const gcond
*cond_stmt
= dyn_cast
<const gcond
*> (last_stmt
))
729 enum tree_code op
= gimple_cond_code (cond_stmt
);
730 tree lhs
= gimple_cond_lhs (cond_stmt
);
731 tree rhs
= gimple_cond_rhs (cond_stmt
);
732 if (cfg_sedge
.false_value_p ())
733 op
= invert_tree_comparison (op
, false /* honor_nans */);
734 return maybe_describe_condition (can_colorize
,
738 return label_text::borrow (NULL
);
741 /* Subroutine of maybe_describe_condition above.
743 Attempt to generate a user-facing description of the condition
744 LHS OP RHS, but only if it is likely to make it easier for the
745 user to understand a condition. */
748 start_cfg_edge_event::maybe_describe_condition (bool can_colorize
,
753 /* In theory we could just build a tree via
754 fold_build2 (op, boolean_type_node, lhs, rhs)
755 and print it with %qE on it, but this leads to warts such as
756 parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
758 /* Special-case: describe testing the result of strcmp, as figuring
759 out what the "true" or "false" path is can be confusing to the user. */
760 if (TREE_CODE (lhs
) == SSA_NAME
763 if (gcall
*call
= dyn_cast
<gcall
*> (SSA_NAME_DEF_STMT (lhs
)))
764 if (is_special_named_call_p (call
, "strcmp", 2))
767 return label_text::borrow ("when the strings are equal");
769 return label_text::borrow ("when the strings are non-equal");
773 /* Only attempt to generate text for sufficiently simple expressions. */
774 if (!should_print_expr_p (lhs
))
775 return label_text::borrow (NULL
);
776 if (!should_print_expr_p (rhs
))
777 return label_text::borrow (NULL
);
779 /* Special cases for pointer comparisons against NULL. */
780 if (POINTER_TYPE_P (TREE_TYPE (lhs
))
781 && POINTER_TYPE_P (TREE_TYPE (rhs
))
785 return make_label_text (can_colorize
, "when %qE is NULL",
788 return make_label_text (can_colorize
, "when %qE is non-NULL",
792 return make_label_text (can_colorize
, "when %<%E %s %E%>",
793 lhs
, op_symbol_code (op
), rhs
);
796 /* Subroutine of maybe_describe_condition.
798 Return true if EXPR is we will get suitable user-facing output
802 start_cfg_edge_event::should_print_expr_p (tree expr
)
804 if (TREE_CODE (expr
) == SSA_NAME
)
806 if (SSA_NAME_VAR (expr
))
807 return should_print_expr_p (SSA_NAME_VAR (expr
));
815 if (CONSTANT_CLASS_P (expr
))
821 /* class call_event : public superedge_event. */
823 /* call_event's ctor. */
825 call_event::call_event (const exploded_edge
&eedge
,
826 const event_loc_info
&loc_info
)
827 : superedge_event (EK_CALL_EDGE
, eedge
, loc_info
)
830 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_CALL
);
832 m_src_snode
= eedge
.m_src
->get_supernode ();
833 m_dest_snode
= eedge
.m_dest
->get_supernode ();
836 /* Implementation of diagnostic_event::get_desc vfunc for
839 If this call event passes critical state for an sm-based warning,
840 allow the diagnostic to generate a precise description, such as:
842 "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
844 Otherwise, generate a description of the form
845 "calling 'foo' from 'bar'". */
848 call_event::get_desc (bool can_colorize
) const
850 if (m_critical_state
&& m_pending_diagnostic
)
853 tree var
= fixup_tree_for_diagnostic (m_var
);
854 label_text custom_desc
855 = m_pending_diagnostic
->describe_call_with_state
856 (evdesc::call_with_state (can_colorize
,
857 m_src_snode
->m_fun
->decl
,
858 m_dest_snode
->m_fun
->decl
,
861 if (custom_desc
.get ())
865 return make_label_text (can_colorize
,
866 "calling %qE from %qE",
867 get_callee_fndecl (),
868 get_caller_fndecl ());
871 /* Implementation of diagnostic_event::get_meaning vfunc for
872 function call events. */
874 diagnostic_event::meaning
875 call_event::get_meaning () const
877 return meaning (VERB_call
, NOUN_function
);
880 /* Override of checker_event::is_call_p for calls. */
883 call_event::is_call_p () const
889 call_event::get_caller_fndecl () const
891 return m_src_snode
->m_fun
->decl
;
895 call_event::get_callee_fndecl () const
897 return m_dest_snode
->m_fun
->decl
;
900 /* class return_event : public superedge_event. */
902 /* return_event's ctor. */
904 return_event::return_event (const exploded_edge
&eedge
,
905 const event_loc_info
&loc_info
)
906 : superedge_event (EK_RETURN_EDGE
, eedge
, loc_info
)
909 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_RETURN
);
911 m_src_snode
= eedge
.m_src
->get_supernode ();
912 m_dest_snode
= eedge
.m_dest
->get_supernode ();
915 /* Implementation of diagnostic_event::get_desc vfunc for
918 If this return event returns critical state for an sm-based warning,
919 allow the diagnostic to generate a precise description, such as:
921 "possible of NULL to 'foo' from 'bar'"
923 Otherwise, generate a description of the form
924 "returning to 'foo' from 'bar'. */
927 return_event::get_desc (bool can_colorize
) const
929 /* For greatest precision-of-wording, if this is returning the
930 state involved in the pending diagnostic, give the pending
931 diagnostic a chance to describe this return (in terms of
933 if (m_critical_state
&& m_pending_diagnostic
)
935 label_text custom_desc
936 = m_pending_diagnostic
->describe_return_of_state
937 (evdesc::return_of_state (can_colorize
,
938 m_dest_snode
->m_fun
->decl
,
939 m_src_snode
->m_fun
->decl
,
941 if (custom_desc
.get ())
944 return make_label_text (can_colorize
,
945 "returning to %qE from %qE",
946 m_dest_snode
->m_fun
->decl
,
947 m_src_snode
->m_fun
->decl
);
950 /* Implementation of diagnostic_event::get_meaning vfunc for
951 function return events. */
953 diagnostic_event::meaning
954 return_event::get_meaning () const
956 return meaning (VERB_return
, NOUN_function
);
959 /* Override of checker_event::is_return_p for returns. */
962 return_event::is_return_p () const
967 /* class start_consolidated_cfg_edges_event : public checker_event. */
970 start_consolidated_cfg_edges_event::get_desc (bool can_colorize
) const
972 return make_label_text (can_colorize
,
973 "following %qs branch...",
974 m_edge_sense
? "true" : "false");
977 /* Implementation of diagnostic_event::get_meaning vfunc for
978 start_consolidated_cfg_edges_event. */
980 diagnostic_event::meaning
981 start_consolidated_cfg_edges_event::get_meaning () const
983 return meaning (VERB_branch
,
984 (m_edge_sense
? PROPERTY_true
: PROPERTY_false
));
987 /* class inlined_call_event : public checker_event. */
990 inlined_call_event::get_desc (bool can_colorize
) const
992 return make_label_text (can_colorize
,
993 "inlined call to %qE from %qE",
994 m_apparent_callee_fndecl
,
995 m_apparent_caller_fndecl
);
998 /* Implementation of diagnostic_event::get_meaning vfunc for
999 reconstructed inlined function calls. */
1001 diagnostic_event::meaning
1002 inlined_call_event::get_meaning () const
1004 return meaning (VERB_call
, NOUN_function
);
1007 /* class setjmp_event : public checker_event. */
1009 /* Implementation of diagnostic_event::get_desc vfunc for
1013 setjmp_event::get_desc (bool can_colorize
) const
1015 return make_label_text (can_colorize
,
1017 get_user_facing_name (m_setjmp_call
));
1020 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1022 Record this setjmp's event ID into the path, so that rewind events can
1026 setjmp_event::prepare_for_emission (checker_path
*path
,
1027 pending_diagnostic
*pd
,
1028 diagnostic_event_id_t emission_id
)
1030 checker_event::prepare_for_emission (path
, pd
, emission_id
);
1031 path
->record_setjmp_event (m_enode
, emission_id
);
1034 /* class rewind_event : public checker_event. */
1036 /* Get the fndecl containing the site of the longjmp call. */
1039 rewind_event::get_longjmp_caller () const
1041 return m_eedge
->m_src
->get_function ()->decl
;
1044 /* Get the fndecl containing the site of the setjmp call. */
1047 rewind_event::get_setjmp_caller () const
1049 return m_eedge
->m_dest
->get_function ()->decl
;
1052 /* rewind_event's ctor. */
1054 rewind_event::rewind_event (const exploded_edge
*eedge
,
1055 enum event_kind kind
,
1056 const event_loc_info
&loc_info
,
1057 const rewind_info_t
*rewind_info
)
1058 : checker_event (kind
, loc_info
),
1059 m_rewind_info (rewind_info
),
1062 gcc_assert (m_eedge
->m_custom_info
.get () == m_rewind_info
);
1065 /* class rewind_from_longjmp_event : public rewind_event. */
1067 /* Implementation of diagnostic_event::get_desc vfunc for
1068 rewind_from_longjmp_event. */
1071 rewind_from_longjmp_event::get_desc (bool can_colorize
) const
1073 const char *src_name
1074 = get_user_facing_name (m_rewind_info
->get_longjmp_call ());
1076 if (get_longjmp_caller () == get_setjmp_caller ())
1077 /* Special-case: purely intraprocedural rewind. */
1078 return make_label_text (can_colorize
,
1079 "rewinding within %qE from %qs...",
1080 get_longjmp_caller (),
1083 return make_label_text (can_colorize
,
1084 "rewinding from %qs in %qE...",
1086 get_longjmp_caller ());
1089 /* class rewind_to_setjmp_event : public rewind_event. */
1091 /* Implementation of diagnostic_event::get_desc vfunc for
1092 rewind_to_setjmp_event. */
1095 rewind_to_setjmp_event::get_desc (bool can_colorize
) const
1097 const char *dst_name
1098 = get_user_facing_name (m_rewind_info
->get_setjmp_call ());
1100 /* If we can, identify the ID of the setjmp_event. */
1101 if (m_original_setjmp_event_id
.known_p ())
1103 if (get_longjmp_caller () == get_setjmp_caller ())
1104 /* Special-case: purely intraprocedural rewind. */
1105 return make_label_text (can_colorize
,
1106 "...to %qs (saved at %@)",
1108 &m_original_setjmp_event_id
);
1110 return make_label_text (can_colorize
,
1111 "...to %qs in %qE (saved at %@)",
1113 get_setjmp_caller (),
1114 &m_original_setjmp_event_id
);
1118 if (get_longjmp_caller () == get_setjmp_caller ())
1119 /* Special-case: purely intraprocedural rewind. */
1120 return make_label_text (can_colorize
,
1123 get_setjmp_caller ());
1125 return make_label_text (can_colorize
,
1128 get_setjmp_caller ());
1132 /* Implementation of checker_event::prepare_for_emission vfunc for
1133 rewind_to_setjmp_event.
1135 Attempt to look up the setjmp event ID that recorded the jmp_buf
1139 rewind_to_setjmp_event::prepare_for_emission (checker_path
*path
,
1140 pending_diagnostic
*pd
,
1141 diagnostic_event_id_t emission_id
)
1143 checker_event::prepare_for_emission (path
, pd
, emission_id
);
1144 path
->get_setjmp_event (m_rewind_info
->get_enode_origin (),
1145 &m_original_setjmp_event_id
);
1148 /* class warning_event : public checker_event. */
1150 /* Implementation of diagnostic_event::get_desc vfunc for
1153 If the pending diagnostic implements describe_final_event, use it,
1154 generating a precise description e.g.
1155 "second 'free' here; first 'free' was at (7)"
1157 Otherwise generate a generic description. */
1160 warning_event::get_desc (bool can_colorize
) const
1162 if (m_pending_diagnostic
)
1164 tree var
= fixup_tree_for_diagnostic (m_var
);
1166 = m_pending_diagnostic
->describe_final_event
1167 (evdesc::final_event (can_colorize
, var
, m_state
, *this));
1170 if (m_sm
&& flag_analyzer_verbose_state_changes
)
1173 return make_label_text (can_colorize
,
1174 "%s (%qE is in state %qs)",
1176 var
, m_state
->get_name ());
1178 return make_label_text (can_colorize
,
1179 "%s (in global state %qs)",
1181 m_state
->get_name ());
1191 return make_label_text (can_colorize
,
1192 "here (%qE is in state %qs)",
1193 m_var
, m_state
->get_name ());
1195 return make_label_text (can_colorize
,
1196 "here (in global state %qs)",
1197 m_state
->get_name ());
1200 return label_text::borrow ("here");
1203 /* Implementation of diagnostic_event::get_meaning vfunc for
1206 diagnostic_event::meaning
1207 warning_event::get_meaning () const
1209 return meaning (VERB_danger
, NOUN_unknown
);
1214 #endif /* #if ENABLE_ANALYZER */