1 /* Subclasses of diagnostic_event for analyzer diagnostics.
2 Copyright (C) 2019-2023 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 const exploded_node
*enode
)
415 : checker_event (EK_STATE_CHANGE
,
416 event_loc_info (stmt
->location
,
419 m_node (node
), m_stmt (stmt
), m_sm (sm
),
420 m_sval (sval
), m_from (from
), m_to (to
),
422 m_dst_state (dst_state
),
427 /* Implementation of diagnostic_event::get_desc vfunc for
430 Attempt to generate a nicer human-readable description.
431 For greatest precision-of-wording, give the pending diagnostic
432 a chance to describe this state change (in terms of the
434 Note that we only have a pending_diagnostic set on the event once
435 the diagnostic is about to being emitted, so the description for
436 an event can change. */
439 state_change_event::get_desc (bool can_colorize
) const
441 if (m_pending_diagnostic
)
443 region_model
*model
= m_dst_state
.m_region_model
;
444 tree var
= model
->get_representative_tree (m_sval
);
445 tree origin
= model
->get_representative_tree (m_origin
);
446 label_text custom_desc
447 = m_pending_diagnostic
->describe_state_change
448 (evdesc::state_change (can_colorize
, var
, origin
,
449 m_from
, m_to
, m_emission_id
, *this));
450 if (custom_desc
.get ())
452 if (flag_analyzer_verbose_state_changes
)
454 /* Get any "meaning" of event. */
455 diagnostic_event::meaning meaning
= get_meaning ();
456 pretty_printer meaning_pp
;
457 meaning
.dump_to_pp (&meaning_pp
);
459 /* Append debug version. */
461 return make_label_text
463 "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
469 pp_formatted_text (&meaning_pp
));
471 return make_label_text
473 "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
478 pp_formatted_text (&meaning_pp
));
485 /* Fallback description. */
488 label_text sval_desc
= m_sval
->get_desc ();
491 label_text origin_desc
= m_origin
->get_desc ();
492 return make_label_text
494 "state of %qs: %qs -> %qs (origin: %qs)",
501 return make_label_text
503 "state of %qs: %qs -> %qs (NULL origin)",
510 gcc_assert (m_origin
== NULL
);
511 return make_label_text
513 "global state: %qs -> %qs",
519 /* Implementation of diagnostic_event::get_meaning vfunc for
520 state change events: delegate to the pending_diagnostic to
523 diagnostic_event::meaning
524 state_change_event::get_meaning () const
526 if (m_pending_diagnostic
)
528 region_model
*model
= m_dst_state
.m_region_model
;
529 tree var
= model
->get_representative_tree (m_sval
);
530 tree origin
= model
->get_representative_tree (m_origin
);
531 return m_pending_diagnostic
->get_meaning_for_state_change
532 (evdesc::state_change (false, var
, origin
,
533 m_from
, m_to
, m_emission_id
, *this));
539 /* class superedge_event : public checker_event. */
541 /* Get the callgraph_superedge for this superedge_event, which must be
542 for an interprocedural edge, rather than a CFG edge. */
544 const callgraph_superedge
&
545 superedge_event::get_callgraph_superedge () const
547 gcc_assert (m_sedge
->m_kind
!= SUPEREDGE_CFG_EDGE
);
548 return *m_sedge
->dyn_cast_callgraph_superedge ();
551 /* Determine if this event should be filtered at the given verbosity
555 superedge_event::should_filter_p (int verbosity
) const
557 switch (m_sedge
->m_kind
)
559 case SUPEREDGE_CFG_EDGE
:
566 /* Filter events with empty descriptions. This ought to filter
567 FALLTHRU, but retain true/false/switch edges. */
568 label_text desc
= get_desc (false);
569 gcc_assert (desc
.get ());
570 if (desc
.get ()[0] == '\0')
582 /* superedge_event's ctor. */
584 superedge_event::superedge_event (enum event_kind kind
,
585 const exploded_edge
&eedge
,
586 const event_loc_info
&loc_info
)
587 : checker_event (kind
, loc_info
),
588 m_eedge (eedge
), m_sedge (eedge
.m_sedge
),
589 m_var (NULL_TREE
), m_critical_state (0)
593 /* class cfg_edge_event : public superedge_event. */
595 /* Get the cfg_superedge for this cfg_edge_event. */
597 const cfg_superedge
&
598 cfg_edge_event::get_cfg_superedge () const
600 return *m_sedge
->dyn_cast_cfg_superedge ();
603 /* cfg_edge_event's ctor. */
605 cfg_edge_event::cfg_edge_event (enum event_kind kind
,
606 const exploded_edge
&eedge
,
607 const event_loc_info
&loc_info
)
608 : superedge_event (kind
, eedge
, loc_info
)
610 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_CFG_EDGE
);
613 /* Implementation of diagnostic_event::get_meaning vfunc for
616 diagnostic_event::meaning
617 cfg_edge_event::get_meaning () const
619 const cfg_superedge
& cfg_sedge
= get_cfg_superedge ();
620 if (cfg_sedge
.true_value_p ())
621 return meaning (VERB_branch
, PROPERTY_true
);
622 else if (cfg_sedge
.false_value_p ())
623 return meaning (VERB_branch
, PROPERTY_false
);
628 /* class start_cfg_edge_event : public cfg_edge_event. */
630 /* Implementation of diagnostic_event::get_desc vfunc for
631 start_cfg_edge_event.
633 If -fanalyzer-verbose-edges, then generate low-level descriptions, such
635 "taking 'true' edge SN:7 -> SN:8".
637 Otherwise, generate strings using the label of the underlying CFG if
639 "following 'true' branch..." or
640 "following 'case 3' branch..."
641 "following 'default' branch..."
643 For conditionals, attempt to supply a description of the condition that
645 "following 'false' branch (when 'ptr' is non-NULL)..."
647 Failing that, return an empty description (which will lead to this event
651 start_cfg_edge_event::get_desc (bool can_colorize
) const
653 bool user_facing
= !flag_analyzer_verbose_edges
;
654 label_text
edge_desc (m_sedge
->get_description (user_facing
));
657 if (edge_desc
.get () && strlen (edge_desc
.get ()) > 0)
659 label_text cond_desc
= maybe_describe_condition (can_colorize
);
661 if (cond_desc
.get ())
662 return make_label_text (can_colorize
,
663 "following %qs branch (%s)...",
664 edge_desc
.get (), cond_desc
.get ());
666 return make_label_text (can_colorize
,
667 "following %qs branch...",
671 return label_text::borrow ("");
675 if (strlen (edge_desc
.get ()) > 0)
676 return make_label_text (can_colorize
,
677 "taking %qs edge SN:%i -> SN:%i",
679 m_sedge
->m_src
->m_index
,
680 m_sedge
->m_dest
->m_index
);
682 return make_label_text (can_colorize
,
683 "taking edge SN:%i -> SN:%i",
684 m_sedge
->m_src
->m_index
,
685 m_sedge
->m_dest
->m_index
);
689 /* Attempt to generate a description of any condition that holds at this edge.
691 The intent is to make the user-facing messages more clear, especially for
692 cases where there's a single or double-negative, such as
693 when describing the false branch of an inverted condition.
695 For example, rather than printing just:
700 | (1) following 'false' branch...
702 it's clearer to spell out the condition that holds:
707 | (1) following 'false' branch (when 'ptr' is non-NULL)...
708 ^^^^^^^^^^^^^^^^^^^^^^
710 In the above example, this function would generate the highlighted
711 string: "when 'ptr' is non-NULL".
713 If the edge is not a condition, or it's not clear that a description of
714 the condition would be helpful to the user, return NULL. */
717 start_cfg_edge_event::maybe_describe_condition (bool can_colorize
) const
719 const cfg_superedge
& cfg_sedge
= get_cfg_superedge ();
721 if (cfg_sedge
.true_value_p () || cfg_sedge
.false_value_p ())
723 const gimple
*last_stmt
= m_sedge
->m_src
->get_last_stmt ();
724 if (const gcond
*cond_stmt
= dyn_cast
<const gcond
*> (last_stmt
))
726 enum tree_code op
= gimple_cond_code (cond_stmt
);
727 tree lhs
= gimple_cond_lhs (cond_stmt
);
728 tree rhs
= gimple_cond_rhs (cond_stmt
);
729 if (cfg_sedge
.false_value_p ())
730 op
= invert_tree_comparison (op
, false /* honor_nans */);
731 return maybe_describe_condition (can_colorize
,
735 return label_text::borrow (NULL
);
738 /* Subroutine of maybe_describe_condition above.
740 Attempt to generate a user-facing description of the condition
741 LHS OP RHS, but only if it is likely to make it easier for the
742 user to understand a condition. */
745 start_cfg_edge_event::maybe_describe_condition (bool can_colorize
,
750 /* In theory we could just build a tree via
751 fold_build2 (op, boolean_type_node, lhs, rhs)
752 and print it with %qE on it, but this leads to warts such as
753 parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
755 /* Special-case: describe testing the result of strcmp, as figuring
756 out what the "true" or "false" path is can be confusing to the user. */
757 if (TREE_CODE (lhs
) == SSA_NAME
760 if (gcall
*call
= dyn_cast
<gcall
*> (SSA_NAME_DEF_STMT (lhs
)))
761 if (is_special_named_call_p (call
, "strcmp", 2))
764 return label_text::borrow ("when the strings are equal");
766 return label_text::borrow ("when the strings are non-equal");
770 /* Only attempt to generate text for sufficiently simple expressions. */
771 if (!should_print_expr_p (lhs
))
772 return label_text::borrow (NULL
);
773 if (!should_print_expr_p (rhs
))
774 return label_text::borrow (NULL
);
776 /* Special cases for pointer comparisons against NULL. */
777 if (POINTER_TYPE_P (TREE_TYPE (lhs
))
778 && POINTER_TYPE_P (TREE_TYPE (rhs
))
782 return make_label_text (can_colorize
, "when %qE is NULL",
785 return make_label_text (can_colorize
, "when %qE is non-NULL",
789 return make_label_text (can_colorize
, "when %<%E %s %E%>",
790 lhs
, op_symbol_code (op
), rhs
);
793 /* Subroutine of maybe_describe_condition.
795 Return true if EXPR is we will get suitable user-facing output
799 start_cfg_edge_event::should_print_expr_p (tree expr
)
801 if (TREE_CODE (expr
) == SSA_NAME
)
803 if (SSA_NAME_VAR (expr
))
804 return should_print_expr_p (SSA_NAME_VAR (expr
));
812 if (CONSTANT_CLASS_P (expr
))
818 /* class call_event : public superedge_event. */
820 /* call_event's ctor. */
822 call_event::call_event (const exploded_edge
&eedge
,
823 const event_loc_info
&loc_info
)
824 : superedge_event (EK_CALL_EDGE
, eedge
, loc_info
)
827 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_CALL
);
829 m_src_snode
= eedge
.m_src
->get_supernode ();
830 m_dest_snode
= eedge
.m_dest
->get_supernode ();
833 /* Implementation of diagnostic_event::get_desc vfunc for
836 If this call event passes critical state for an sm-based warning,
837 allow the diagnostic to generate a precise description, such as:
839 "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
841 Otherwise, generate a description of the form
842 "calling 'foo' from 'bar'". */
845 call_event::get_desc (bool can_colorize
) const
847 if (m_critical_state
&& m_pending_diagnostic
)
850 tree var
= fixup_tree_for_diagnostic (m_var
);
851 label_text custom_desc
852 = m_pending_diagnostic
->describe_call_with_state
853 (evdesc::call_with_state (can_colorize
,
854 m_src_snode
->m_fun
->decl
,
855 m_dest_snode
->m_fun
->decl
,
858 if (custom_desc
.get ())
862 return make_label_text (can_colorize
,
863 "calling %qE from %qE",
864 get_callee_fndecl (),
865 get_caller_fndecl ());
868 /* Implementation of diagnostic_event::get_meaning vfunc for
869 function call events. */
871 diagnostic_event::meaning
872 call_event::get_meaning () const
874 return meaning (VERB_call
, NOUN_function
);
877 /* Override of checker_event::is_call_p for calls. */
880 call_event::is_call_p () const
886 call_event::get_caller_fndecl () const
888 return m_src_snode
->m_fun
->decl
;
892 call_event::get_callee_fndecl () const
894 return m_dest_snode
->m_fun
->decl
;
897 /* class return_event : public superedge_event. */
899 /* return_event's ctor. */
901 return_event::return_event (const exploded_edge
&eedge
,
902 const event_loc_info
&loc_info
)
903 : superedge_event (EK_RETURN_EDGE
, eedge
, loc_info
)
906 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_RETURN
);
908 m_src_snode
= eedge
.m_src
->get_supernode ();
909 m_dest_snode
= eedge
.m_dest
->get_supernode ();
912 /* Implementation of diagnostic_event::get_desc vfunc for
915 If this return event returns critical state for an sm-based warning,
916 allow the diagnostic to generate a precise description, such as:
918 "possible of NULL to 'foo' from 'bar'"
920 Otherwise, generate a description of the form
921 "returning to 'foo' from 'bar'. */
924 return_event::get_desc (bool can_colorize
) const
926 /* For greatest precision-of-wording, if this is returning the
927 state involved in the pending diagnostic, give the pending
928 diagnostic a chance to describe this return (in terms of
930 if (m_critical_state
&& m_pending_diagnostic
)
932 label_text custom_desc
933 = m_pending_diagnostic
->describe_return_of_state
934 (evdesc::return_of_state (can_colorize
,
935 m_dest_snode
->m_fun
->decl
,
936 m_src_snode
->m_fun
->decl
,
938 if (custom_desc
.get ())
941 return make_label_text (can_colorize
,
942 "returning to %qE from %qE",
943 m_dest_snode
->m_fun
->decl
,
944 m_src_snode
->m_fun
->decl
);
947 /* Implementation of diagnostic_event::get_meaning vfunc for
948 function return events. */
950 diagnostic_event::meaning
951 return_event::get_meaning () const
953 return meaning (VERB_return
, NOUN_function
);
956 /* Override of checker_event::is_return_p for returns. */
959 return_event::is_return_p () const
964 /* class start_consolidated_cfg_edges_event : public checker_event. */
967 start_consolidated_cfg_edges_event::get_desc (bool can_colorize
) const
969 return make_label_text (can_colorize
,
970 "following %qs branch...",
971 m_edge_sense
? "true" : "false");
974 /* Implementation of diagnostic_event::get_meaning vfunc for
975 start_consolidated_cfg_edges_event. */
977 diagnostic_event::meaning
978 start_consolidated_cfg_edges_event::get_meaning () const
980 return meaning (VERB_branch
,
981 (m_edge_sense
? PROPERTY_true
: PROPERTY_false
));
984 /* class inlined_call_event : public checker_event. */
987 inlined_call_event::get_desc (bool can_colorize
) const
989 return make_label_text (can_colorize
,
990 "inlined call to %qE from %qE",
991 m_apparent_callee_fndecl
,
992 m_apparent_caller_fndecl
);
995 /* Implementation of diagnostic_event::get_meaning vfunc for
996 reconstructed inlined function calls. */
998 diagnostic_event::meaning
999 inlined_call_event::get_meaning () const
1001 return meaning (VERB_call
, NOUN_function
);
1004 /* class setjmp_event : public checker_event. */
1006 /* Implementation of diagnostic_event::get_desc vfunc for
1010 setjmp_event::get_desc (bool can_colorize
) const
1012 return make_label_text (can_colorize
,
1014 get_user_facing_name (m_setjmp_call
));
1017 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1019 Record this setjmp's event ID into the path, so that rewind events can
1023 setjmp_event::prepare_for_emission (checker_path
*path
,
1024 pending_diagnostic
*pd
,
1025 diagnostic_event_id_t emission_id
)
1027 checker_event::prepare_for_emission (path
, pd
, emission_id
);
1028 path
->record_setjmp_event (m_enode
, emission_id
);
1031 /* class rewind_event : public checker_event. */
1033 /* Get the fndecl containing the site of the longjmp call. */
1036 rewind_event::get_longjmp_caller () const
1038 return m_eedge
->m_src
->get_function ()->decl
;
1041 /* Get the fndecl containing the site of the setjmp call. */
1044 rewind_event::get_setjmp_caller () const
1046 return m_eedge
->m_dest
->get_function ()->decl
;
1049 /* rewind_event's ctor. */
1051 rewind_event::rewind_event (const exploded_edge
*eedge
,
1052 enum event_kind kind
,
1053 const event_loc_info
&loc_info
,
1054 const rewind_info_t
*rewind_info
)
1055 : checker_event (kind
, loc_info
),
1056 m_rewind_info (rewind_info
),
1059 gcc_assert (m_eedge
->m_custom_info
.get () == m_rewind_info
);
1062 /* class rewind_from_longjmp_event : public rewind_event. */
1064 /* Implementation of diagnostic_event::get_desc vfunc for
1065 rewind_from_longjmp_event. */
1068 rewind_from_longjmp_event::get_desc (bool can_colorize
) const
1070 const char *src_name
1071 = get_user_facing_name (m_rewind_info
->get_longjmp_call ());
1073 if (get_longjmp_caller () == get_setjmp_caller ())
1074 /* Special-case: purely intraprocedural rewind. */
1075 return make_label_text (can_colorize
,
1076 "rewinding within %qE from %qs...",
1077 get_longjmp_caller (),
1080 return make_label_text (can_colorize
,
1081 "rewinding from %qs in %qE...",
1083 get_longjmp_caller ());
1086 /* class rewind_to_setjmp_event : public rewind_event. */
1088 /* Implementation of diagnostic_event::get_desc vfunc for
1089 rewind_to_setjmp_event. */
1092 rewind_to_setjmp_event::get_desc (bool can_colorize
) const
1094 const char *dst_name
1095 = get_user_facing_name (m_rewind_info
->get_setjmp_call ());
1097 /* If we can, identify the ID of the setjmp_event. */
1098 if (m_original_setjmp_event_id
.known_p ())
1100 if (get_longjmp_caller () == get_setjmp_caller ())
1101 /* Special-case: purely intraprocedural rewind. */
1102 return make_label_text (can_colorize
,
1103 "...to %qs (saved at %@)",
1105 &m_original_setjmp_event_id
);
1107 return make_label_text (can_colorize
,
1108 "...to %qs in %qE (saved at %@)",
1110 get_setjmp_caller (),
1111 &m_original_setjmp_event_id
);
1115 if (get_longjmp_caller () == get_setjmp_caller ())
1116 /* Special-case: purely intraprocedural rewind. */
1117 return make_label_text (can_colorize
,
1120 get_setjmp_caller ());
1122 return make_label_text (can_colorize
,
1125 get_setjmp_caller ());
1129 /* Implementation of checker_event::prepare_for_emission vfunc for
1130 rewind_to_setjmp_event.
1132 Attempt to look up the setjmp event ID that recorded the jmp_buf
1136 rewind_to_setjmp_event::prepare_for_emission (checker_path
*path
,
1137 pending_diagnostic
*pd
,
1138 diagnostic_event_id_t emission_id
)
1140 checker_event::prepare_for_emission (path
, pd
, emission_id
);
1141 path
->get_setjmp_event (m_rewind_info
->get_enode_origin (),
1142 &m_original_setjmp_event_id
);
1145 /* class warning_event : public checker_event. */
1147 /* Implementation of diagnostic_event::get_desc vfunc for
1150 If the pending diagnostic implements describe_final_event, use it,
1151 generating a precise description e.g.
1152 "second 'free' here; first 'free' was at (7)"
1154 Otherwise generate a generic description. */
1157 warning_event::get_desc (bool can_colorize
) const
1159 if (m_pending_diagnostic
)
1161 tree var
= fixup_tree_for_diagnostic (m_var
);
1163 = m_pending_diagnostic
->describe_final_event
1164 (evdesc::final_event (can_colorize
, var
, m_state
, *this));
1167 if (m_sm
&& flag_analyzer_verbose_state_changes
)
1170 return make_label_text (can_colorize
,
1171 "%s (%qE is in state %qs)",
1173 var
, m_state
->get_name ());
1175 return make_label_text (can_colorize
,
1176 "%s (in global state %qs)",
1178 m_state
->get_name ());
1188 return make_label_text (can_colorize
,
1189 "here (%qE is in state %qs)",
1190 m_var
, m_state
->get_name ());
1192 return make_label_text (can_colorize
,
1193 "here (in global state %qs)",
1194 m_state
->get_name ());
1197 return label_text::borrow ("here");
1200 /* Implementation of diagnostic_event::get_meaning vfunc for
1203 diagnostic_event::meaning
1204 warning_event::get_meaning () const
1206 return meaning (VERB_danger
, NOUN_unknown
);
1211 #endif /* #if ENABLE_ANALYZER */