1 /* Subclasses of diagnostic_path and diagnostic_event for analyzer diagnostics.
2 Copyright (C) 2019-2021 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/>. */
23 #include "coretypes.h"
26 #include "basic-block.h"
28 #include "gimple-pretty-print.h"
29 #include "fold-const.h"
31 #include "diagnostic-path.h"
37 #include "alloc-pool.h"
38 #include "fibonacci_heap.h"
39 #include "diagnostic-event-id.h"
40 #include "shortest-paths.h"
42 #include "analyzer/analyzer.h"
43 #include "analyzer/analyzer-logging.h"
44 #include "analyzer/sm.h"
48 #include "ordered-hash-map.h"
50 #include "analyzer/call-string.h"
51 #include "analyzer/program-point.h"
52 #include "analyzer/store.h"
53 #include "analyzer/region-model.h"
54 #include "analyzer/program-state.h"
55 #include "analyzer/checker-path.h"
56 #include "gimple-iterator.h"
57 #include "analyzer/supergraph.h"
58 #include "analyzer/pending-diagnostic.h"
59 #include "analyzer/diagnostic-manager.h"
60 #include "analyzer/constraint-manager.h"
61 #include "analyzer/diagnostic-manager.h"
62 #include "analyzer/checker-path.h"
63 #include "analyzer/exploded-graph.h"
69 /* Get a string for EK. */
72 event_kind_to_string (enum event_kind ek
)
84 case EK_FUNCTION_ENTRY
:
85 return "EK_FUNCTION_ENTRY";
87 return "EK_STATE_CHANGE";
88 case EK_START_CFG_EDGE
:
89 return "EK_START_CFG_EDGE";
91 return "EK_END_CFG_EDGE";
93 return "EK_CALL_EDGE";
95 return "EK_RETURN_EDGE";
98 case EK_REWIND_FROM_LONGJMP
:
99 return "EK_REWIND_FROM_LONGJMP";
100 case EK_REWIND_TO_SETJMP
:
101 return "EK_REWIND_TO_SETJMP";
107 /* class checker_event : public diagnostic_event. */
109 /* Dump this event to PP (for debugging/logging purposes). */
112 checker_event::dump (pretty_printer
*pp
) const
114 label_text
event_desc (get_desc (false));
115 pp_printf (pp
, "\"%s\" (depth %i, m_loc=%x)",
119 event_desc
.maybe_free ();
122 /* Hook for being notified when this event has its final id EMISSION_ID
123 and is about to emitted for PD.
125 Base implementation of checker_event::prepare_for_emission vfunc;
126 subclasses that override this should chain up to it.
128 Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
129 side-effects of the call to get_desc take place before
130 pending_diagnostic::emit is called.
132 For example, state_change_event::get_desc can call
133 pending_diagnostic::describe_state_change; free_of_non_heap can use this
134 to tweak the message (TODO: would be neater to simply capture the
135 pertinent data within the sm-state). */
138 checker_event::prepare_for_emission (checker_path
*,
139 pending_diagnostic
*pd
,
140 diagnostic_event_id_t emission_id
)
142 m_pending_diagnostic
= pd
;
143 m_emission_id
= emission_id
;
145 label_text desc
= get_desc (false);
149 /* class debug_event : public checker_event. */
151 /* Implementation of diagnostic_event::get_desc vfunc for
153 Use the saved string as the event's description. */
156 debug_event::get_desc (bool) const
158 return label_text::borrow (m_desc
);
161 /* class custom_event : public checker_event. */
163 /* Implementation of diagnostic_event::get_desc vfunc for
165 Use the saved string as the event's description. */
168 custom_event::get_desc (bool) const
170 return label_text::borrow (m_desc
);
173 /* class statement_event : public checker_event. */
175 /* statement_event's ctor. */
177 statement_event::statement_event (const gimple
*stmt
, tree fndecl
, int depth
,
178 const program_state
&dst_state
)
179 : checker_event (EK_STMT
, gimple_location (stmt
), fndecl
, depth
),
181 m_dst_state (dst_state
)
185 /* Implementation of diagnostic_event::get_desc vfunc for
187 Use the statement's dump form as the event's description. */
190 statement_event::get_desc (bool) const
193 pp_string (&pp
, "stmt: ");
194 pp_gimple_stmt_1 (&pp
, m_stmt
, 0, (dump_flags_t
)0);
195 return label_text::take (xstrdup (pp_formatted_text (&pp
)));
198 /* class function_entry_event : public checker_event. */
200 /* Implementation of diagnostic_event::get_desc vfunc for
201 function_entry_event.
203 Use a string such as "entry to 'foo'" as the event's description. */
206 function_entry_event::get_desc (bool can_colorize
) const
208 return make_label_text (can_colorize
, "entry to %qE", m_fndecl
);
211 /* class state_change_event : public checker_event. */
213 /* state_change_event's ctor. */
215 state_change_event::state_change_event (const supernode
*node
,
218 const state_machine
&sm
,
220 state_machine::state_t from
,
221 state_machine::state_t to
,
222 const svalue
*origin
,
223 const program_state
&dst_state
)
224 : checker_event (EK_STATE_CHANGE
,
225 stmt
->location
, node
->m_fun
->decl
,
227 m_node (node
), m_stmt (stmt
), m_sm (sm
),
228 m_sval (sval
), m_from (from
), m_to (to
),
230 m_dst_state (dst_state
)
234 /* Implementation of diagnostic_event::get_desc vfunc for
237 Attempt to generate a nicer human-readable description.
238 For greatest precision-of-wording, give the pending diagnostic
239 a chance to describe this state change (in terms of the
241 Note that we only have a pending_diagnostic set on the event once
242 the diagnostic is about to being emitted, so the description for
243 an event can change. */
246 state_change_event::get_desc (bool can_colorize
) const
248 if (m_pending_diagnostic
)
250 region_model
*model
= m_dst_state
.m_region_model
;
251 tree var
= model
->get_representative_tree (m_sval
);
252 tree origin
= model
->get_representative_tree (m_origin
);
253 label_text custom_desc
254 = m_pending_diagnostic
->describe_state_change
255 (evdesc::state_change (can_colorize
, var
, origin
,
256 m_from
, m_to
, m_emission_id
, *this));
257 if (custom_desc
.m_buffer
)
259 if (flag_analyzer_verbose_state_changes
)
261 /* Append debug version. */
264 result
= make_label_text
266 "%s (state of %qE: %qs -> %qs, origin: %qE)",
267 custom_desc
.m_buffer
,
273 result
= make_label_text
275 "%s (state of %qE: %qs -> %qs, NULL origin)",
276 custom_desc
.m_buffer
,
280 custom_desc
.maybe_free ();
288 /* Fallback description. */
291 label_text sval_desc
= m_sval
->get_desc ();
294 label_text origin_desc
= m_origin
->get_desc ();
295 return make_label_text
297 "state of %qs: %qs -> %qs (origin: %qs)",
301 origin_desc
.m_buffer
);
304 return make_label_text
306 "state of %qs: %qs -> %qs (NULL origin)",
313 gcc_assert (m_origin
== NULL
);
314 return make_label_text
316 "global state: %qs -> %qs",
322 /* class superedge_event : public checker_event. */
324 /* Get the callgraph_superedge for this superedge_event, which must be
325 for an interprocedural edge, rather than a CFG edge. */
327 const callgraph_superedge
&
328 superedge_event::get_callgraph_superedge () const
330 gcc_assert (m_sedge
->m_kind
!= SUPEREDGE_CFG_EDGE
);
331 return *m_sedge
->dyn_cast_callgraph_superedge ();
334 /* Determine if this event should be filtered at the given verbosity
338 superedge_event::should_filter_p (int verbosity
) const
340 switch (m_sedge
->m_kind
)
342 case SUPEREDGE_CFG_EDGE
:
349 /* Filter events with empty descriptions. This ought to filter
350 FALLTHRU, but retain true/false/switch edges. */
351 label_text desc
= get_desc (false);
352 gcc_assert (desc
.m_buffer
);
353 if (desc
.m_buffer
[0] == '\0')
366 /* superedge_event's ctor. */
368 superedge_event::superedge_event (enum event_kind kind
,
369 const exploded_edge
&eedge
,
370 location_t loc
, tree fndecl
, int depth
)
371 : checker_event (kind
, loc
, fndecl
, depth
),
372 m_eedge (eedge
), m_sedge (eedge
.m_sedge
),
373 m_var (NULL_TREE
), m_critical_state (0)
377 /* class cfg_edge_event : public superedge_event. */
379 /* Get the cfg_superedge for this cfg_edge_event. */
381 const cfg_superedge
&
382 cfg_edge_event::get_cfg_superedge () const
384 return *m_sedge
->dyn_cast_cfg_superedge ();
387 /* cfg_edge_event's ctor. */
389 cfg_edge_event::cfg_edge_event (enum event_kind kind
,
390 const exploded_edge
&eedge
,
391 location_t loc
, tree fndecl
, int depth
)
392 : superedge_event (kind
, eedge
, loc
, fndecl
, depth
)
394 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_CFG_EDGE
);
397 /* class start_cfg_edge_event : public cfg_edge_event. */
399 /* Implementation of diagnostic_event::get_desc vfunc for
400 start_cfg_edge_event.
402 If -fanalyzer-verbose-edges, then generate low-level descriptions, such
404 "taking 'true' edge SN:7 -> SN:8".
406 Otherwise, generate strings using the label of the underlying CFG if
408 "following 'true' branch..." or
409 "following 'case 3' branch..."
410 "following 'default' branch..."
412 For conditionals, attempt to supply a description of the condition that
414 "following 'false' branch (when 'ptr' is non-NULL)..."
416 Failing that, return an empty description (which will lead to this event
420 start_cfg_edge_event::get_desc (bool can_colorize
) const
422 bool user_facing
= !flag_analyzer_verbose_edges
;
423 char *edge_desc
= m_sedge
->get_description (user_facing
);
426 if (edge_desc
&& strlen (edge_desc
) > 0)
428 label_text cond_desc
= maybe_describe_condition (can_colorize
);
430 if (cond_desc
.m_buffer
)
432 result
= make_label_text (can_colorize
,
433 "following %qs branch (%s)...",
434 edge_desc
, cond_desc
.m_buffer
);
435 cond_desc
.maybe_free ();
439 result
= make_label_text (can_colorize
,
440 "following %qs branch...",
449 return label_text::borrow ("");
454 if (strlen (edge_desc
) > 0)
457 = make_label_text (can_colorize
,
458 "taking %qs edge SN:%i -> SN:%i",
460 m_sedge
->m_src
->m_index
,
461 m_sedge
->m_dest
->m_index
);
468 return make_label_text (can_colorize
,
469 "taking edge SN:%i -> SN:%i",
470 m_sedge
->m_src
->m_index
,
471 m_sedge
->m_dest
->m_index
);
476 /* Attempt to generate a description of any condition that holds at this edge.
478 The intent is to make the user-facing messages more clear, especially for
479 cases where there's a single or double-negative, such as
480 when describing the false branch of an inverted condition.
482 For example, rather than printing just:
487 | (1) following 'false' branch...
489 it's clearer to spell out the condition that holds:
494 | (1) following 'false' branch (when 'ptr' is non-NULL)...
495 ^^^^^^^^^^^^^^^^^^^^^^
497 In the above example, this function would generate the highlighted
498 string: "when 'ptr' is non-NULL".
500 If the edge is not a condition, or it's not clear that a description of
501 the condition would be helpful to the user, return NULL. */
504 start_cfg_edge_event::maybe_describe_condition (bool can_colorize
) const
506 const cfg_superedge
& cfg_sedge
= get_cfg_superedge ();
508 if (cfg_sedge
.true_value_p () || cfg_sedge
.false_value_p ())
510 const gimple
*last_stmt
= m_sedge
->m_src
->get_last_stmt ();
511 if (const gcond
*cond_stmt
= dyn_cast
<const gcond
*> (last_stmt
))
513 enum tree_code op
= gimple_cond_code (cond_stmt
);
514 tree lhs
= gimple_cond_lhs (cond_stmt
);
515 tree rhs
= gimple_cond_rhs (cond_stmt
);
516 if (cfg_sedge
.false_value_p ())
517 op
= invert_tree_comparison (op
, false /* honor_nans */);
518 return maybe_describe_condition (can_colorize
,
522 return label_text::borrow (NULL
);
525 /* Subroutine of maybe_describe_condition above.
527 Attempt to generate a user-facing description of the condition
528 LHS OP RHS, but only if it is likely to make it easier for the
529 user to understand a condition. */
532 start_cfg_edge_event::maybe_describe_condition (bool can_colorize
,
537 /* In theory we could just build a tree via
538 fold_build2 (op, boolean_type_node, lhs, rhs)
539 and print it with %qE on it, but this leads to warts such as
540 parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
542 /* Special-case: describe testing the result of strcmp, as figuring
543 out what the "true" or "false" path is can be confusing to the user. */
544 if (TREE_CODE (lhs
) == SSA_NAME
547 if (gcall
*call
= dyn_cast
<gcall
*> (SSA_NAME_DEF_STMT (lhs
)))
548 if (is_special_named_call_p (call
, "strcmp", 2))
551 return label_text::borrow ("when the strings are equal");
553 return label_text::borrow ("when the strings are non-equal");
557 /* Only attempt to generate text for sufficiently simple expressions. */
558 if (!should_print_expr_p (lhs
))
559 return label_text::borrow (NULL
);
560 if (!should_print_expr_p (rhs
))
561 return label_text::borrow (NULL
);
563 /* Special cases for pointer comparisons against NULL. */
564 if (POINTER_TYPE_P (TREE_TYPE (lhs
))
565 && POINTER_TYPE_P (TREE_TYPE (rhs
))
569 return make_label_text (can_colorize
, "when %qE is NULL",
572 return make_label_text (can_colorize
, "when %qE is non-NULL",
576 return make_label_text (can_colorize
, "when %<%E %s %E%>",
577 lhs
, op_symbol_code (op
), rhs
);
580 /* Subroutine of maybe_describe_condition.
582 Return true if EXPR is we will get suitable user-facing output
586 start_cfg_edge_event::should_print_expr_p (tree expr
)
588 if (TREE_CODE (expr
) == SSA_NAME
)
590 if (SSA_NAME_VAR (expr
))
591 return should_print_expr_p (SSA_NAME_VAR (expr
));
599 if (CONSTANT_CLASS_P (expr
))
605 /* class call_event : public superedge_event. */
607 /* call_event's ctor. */
609 call_event::call_event (const exploded_edge
&eedge
,
610 location_t loc
, tree fndecl
, int depth
)
611 : superedge_event (EK_CALL_EDGE
, eedge
, loc
, fndecl
, depth
)
613 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_CALL
);
616 /* Implementation of diagnostic_event::get_desc vfunc for
619 If this call event passes critical state for an sm-based warning,
620 allow the diagnostic to generate a precise description, such as:
622 "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
624 Otherwise, generate a description of the form
625 "calling 'foo' from 'bar'". */
628 call_event::get_desc (bool can_colorize
) const
630 if (m_critical_state
&& m_pending_diagnostic
)
633 label_text custom_desc
634 = m_pending_diagnostic
->describe_call_with_state
635 (evdesc::call_with_state (can_colorize
,
636 m_sedge
->m_src
->m_fun
->decl
,
637 m_sedge
->m_dest
->m_fun
->decl
,
640 if (custom_desc
.m_buffer
)
644 return make_label_text (can_colorize
,
645 "calling %qE from %qE",
646 m_sedge
->m_dest
->m_fun
->decl
,
647 m_sedge
->m_src
->m_fun
->decl
);
650 /* Override of checker_event::is_call_p for calls. */
653 call_event::is_call_p () const
658 /* class return_event : public superedge_event. */
660 /* return_event's ctor. */
662 return_event::return_event (const exploded_edge
&eedge
,
663 location_t loc
, tree fndecl
, int depth
)
664 : superedge_event (EK_RETURN_EDGE
, eedge
, loc
, fndecl
, depth
)
666 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_RETURN
);
669 /* Implementation of diagnostic_event::get_desc vfunc for
672 If this return event returns critical state for an sm-based warning,
673 allow the diagnostic to generate a precise description, such as:
675 "possible of NULL to 'foo' from 'bar'"
677 Otherwise, generate a description of the form
678 "returning to 'foo' from 'bar'. */
681 return_event::get_desc (bool can_colorize
) const
683 /* For greatest precision-of-wording, if this is returning the
684 state involved in the pending diagnostic, give the pending
685 diagnostic a chance to describe this return (in terms of
687 if (m_critical_state
&& m_pending_diagnostic
)
689 label_text custom_desc
690 = m_pending_diagnostic
->describe_return_of_state
691 (evdesc::return_of_state (can_colorize
,
692 m_sedge
->m_dest
->m_fun
->decl
,
693 m_sedge
->m_src
->m_fun
->decl
,
695 if (custom_desc
.m_buffer
)
698 return make_label_text (can_colorize
,
699 "returning to %qE from %qE",
700 m_sedge
->m_dest
->m_fun
->decl
,
701 m_sedge
->m_src
->m_fun
->decl
);
704 /* Override of checker_event::is_return_p for returns. */
707 return_event::is_return_p () const
712 /* class setjmp_event : public checker_event. */
714 /* Implementation of diagnostic_event::get_desc vfunc for
718 setjmp_event::get_desc (bool can_colorize
) const
720 return make_label_text (can_colorize
,
722 get_user_facing_name (m_setjmp_call
));
725 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
727 Record this setjmp's event ID into the path, so that rewind events can
731 setjmp_event::prepare_for_emission (checker_path
*path
,
732 pending_diagnostic
*pd
,
733 diagnostic_event_id_t emission_id
)
735 checker_event::prepare_for_emission (path
, pd
, emission_id
);
736 path
->record_setjmp_event (m_enode
, emission_id
);
739 /* class rewind_event : public checker_event. */
741 /* Get the fndecl containing the site of the longjmp call. */
744 rewind_event::get_longjmp_caller () const
746 return m_eedge
->m_src
->get_function ()->decl
;
749 /* Get the fndecl containing the site of the setjmp call. */
752 rewind_event::get_setjmp_caller () const
754 return m_eedge
->m_dest
->get_function ()->decl
;
757 /* rewind_event's ctor. */
759 rewind_event::rewind_event (const exploded_edge
*eedge
,
760 enum event_kind kind
,
761 location_t loc
, tree fndecl
, int depth
,
762 const rewind_info_t
*rewind_info
)
763 : checker_event (kind
, loc
, fndecl
, depth
),
764 m_rewind_info (rewind_info
),
767 gcc_assert (m_eedge
->m_custom_info
== m_rewind_info
);
770 /* class rewind_from_longjmp_event : public rewind_event. */
772 /* Implementation of diagnostic_event::get_desc vfunc for
773 rewind_from_longjmp_event. */
776 rewind_from_longjmp_event::get_desc (bool can_colorize
) const
779 = get_user_facing_name (m_rewind_info
->get_longjmp_call ());
781 if (get_longjmp_caller () == get_setjmp_caller ())
782 /* Special-case: purely intraprocedural rewind. */
783 return make_label_text (can_colorize
,
784 "rewinding within %qE from %qs...",
785 get_longjmp_caller (),
788 return make_label_text (can_colorize
,
789 "rewinding from %qs in %qE...",
791 get_longjmp_caller ());
794 /* class rewind_to_setjmp_event : public rewind_event. */
796 /* Implementation of diagnostic_event::get_desc vfunc for
797 rewind_to_setjmp_event. */
800 rewind_to_setjmp_event::get_desc (bool can_colorize
) const
803 = get_user_facing_name (m_rewind_info
->get_setjmp_call ());
805 /* If we can, identify the ID of the setjmp_event. */
806 if (m_original_setjmp_event_id
.known_p ())
808 if (get_longjmp_caller () == get_setjmp_caller ())
809 /* Special-case: purely intraprocedural rewind. */
810 return make_label_text (can_colorize
,
811 "...to %qs (saved at %@)",
813 &m_original_setjmp_event_id
);
815 return make_label_text (can_colorize
,
816 "...to %qs in %qE (saved at %@)",
818 get_setjmp_caller (),
819 &m_original_setjmp_event_id
);
823 if (get_longjmp_caller () == get_setjmp_caller ())
824 /* Special-case: purely intraprocedural rewind. */
825 return make_label_text (can_colorize
,
828 get_setjmp_caller ());
830 return make_label_text (can_colorize
,
833 get_setjmp_caller ());
837 /* Implementation of checker_event::prepare_for_emission vfunc for
838 rewind_to_setjmp_event.
840 Attempt to look up the setjmp event ID that recorded the jmp_buf
844 rewind_to_setjmp_event::prepare_for_emission (checker_path
*path
,
845 pending_diagnostic
*pd
,
846 diagnostic_event_id_t emission_id
)
848 checker_event::prepare_for_emission (path
, pd
, emission_id
);
849 path
->get_setjmp_event (m_rewind_info
->get_enode_origin (),
850 &m_original_setjmp_event_id
);
853 /* class warning_event : public checker_event. */
855 /* Implementation of diagnostic_event::get_desc vfunc for
858 If the pending diagnostic implements describe_final_event, use it,
859 generating a precise description e.g.
860 "second 'free' here; first 'free' was at (7)"
862 Otherwise generate a generic description. */
865 warning_event::get_desc (bool can_colorize
) const
867 if (m_pending_diagnostic
)
870 = m_pending_diagnostic
->describe_final_event
871 (evdesc::final_event (can_colorize
, m_var
, m_state
));
872 if (ev_desc
.m_buffer
)
874 if (m_sm
&& flag_analyzer_verbose_state_changes
)
878 result
= make_label_text (can_colorize
,
879 "%s (%qE is in state %qs)",
881 m_var
, m_state
->get_name ());
883 result
= make_label_text (can_colorize
,
884 "%s (in global state %qs)",
886 m_state
->get_name ());
887 ev_desc
.maybe_free ();
898 return make_label_text (can_colorize
,
899 "here (%qE is in state %qs)",
900 m_var
, m_state
->get_name ());
902 return make_label_text (can_colorize
,
903 "here (in global state %qs)",
904 m_state
->get_name ());
907 return label_text::borrow ("here");
910 /* Print a single-line representation of this path to PP. */
913 checker_path::dump (pretty_printer
*pp
) const
915 pp_character (pp
, '[');
919 FOR_EACH_VEC_ELT (m_events
, i
, e
)
922 pp_string (pp
, ", ");
923 label_text
event_desc (e
->get_desc (false));
924 pp_printf (pp
, "\"%s\"", event_desc
.m_buffer
);
925 event_desc
.maybe_free ();
927 pp_character (pp
, ']');
930 /* Print a multiline form of this path to LOGGER, prefixing it with DESC. */
933 checker_path::maybe_log (logger
*logger
, const char *desc
) const
937 logger
->start_log_line ();
938 logger
->log_partial ("%s: ", desc
);
939 dump (logger
->get_printer ());
940 logger
->end_log_line ();
941 for (unsigned i
= 0; i
< m_events
.length (); i
++)
943 logger
->start_log_line ();
944 logger
->log_partial ("%s[%i]: %s ", desc
, i
,
945 event_kind_to_string (m_events
[i
]->m_kind
));
946 m_events
[i
]->dump (logger
->get_printer ());
947 logger
->end_log_line ();
951 /* Print a multiline form of this path to STDERR. */
954 checker_path::debug () const
958 FOR_EACH_VEC_ELT (m_events
, i
, e
)
960 label_text
event_desc (e
->get_desc (false));
964 event_kind_to_string (m_events
[i
]->m_kind
),
965 event_desc
.m_buffer
);
966 event_desc
.maybe_free ();
970 /* Add a warning_event to the end of this path. */
973 checker_path::add_final_event (const state_machine
*sm
,
974 const exploded_node
*enode
, const gimple
*stmt
,
975 tree var
, state_machine::state_t state
)
977 checker_event
*end_of_path
978 = new warning_event (get_stmt_location (stmt
, enode
->get_function ()),
979 enode
->get_function ()->decl
,
980 enode
->get_stack_depth (),
982 add_event (end_of_path
);
986 checker_path::fixup_locations (pending_diagnostic
*pd
)
990 FOR_EACH_VEC_ELT (m_events
, i
, e
)
991 e
->set_location (pd
->fixup_location (e
->get_location ()));
996 #endif /* #if ENABLE_ANALYZER */