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";
96 case EK_START_CONSOLIDATED_CFG_EDGES
:
97 return "EK_START_CONSOLIDATED_CFG_EDGES";
98 case EK_END_CONSOLIDATED_CFG_EDGES
:
99 return "EK_END_CONSOLIDATED_CFG_EDGES";
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 /* Dump this event to PP (for debugging/logging purposes). */
116 checker_event::dump (pretty_printer
*pp
) const
118 label_text
event_desc (get_desc (false));
119 pp_printf (pp
, "\"%s\" (depth %i, m_loc=%x)",
123 event_desc
.maybe_free ();
126 /* Hook for being notified when this event has its final id EMISSION_ID
127 and is about to emitted for PD.
129 Base implementation of checker_event::prepare_for_emission vfunc;
130 subclasses that override this should chain up to it.
132 Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
133 side-effects of the call to get_desc take place before
134 pending_diagnostic::emit is called.
136 For example, state_change_event::get_desc can call
137 pending_diagnostic::describe_state_change; free_of_non_heap can use this
138 to tweak the message (TODO: would be neater to simply capture the
139 pertinent data within the sm-state). */
142 checker_event::prepare_for_emission (checker_path
*,
143 pending_diagnostic
*pd
,
144 diagnostic_event_id_t emission_id
)
146 m_pending_diagnostic
= pd
;
147 m_emission_id
= emission_id
;
149 label_text desc
= get_desc (false);
153 /* class debug_event : public checker_event. */
155 /* Implementation of diagnostic_event::get_desc vfunc for
157 Use the saved string as the event's description. */
160 debug_event::get_desc (bool) const
162 return label_text::borrow (m_desc
);
165 /* class precanned_custom_event : public custom_event. */
167 /* Implementation of diagnostic_event::get_desc vfunc for
168 precanned_custom_event.
169 Use the saved string as the event's description. */
172 precanned_custom_event::get_desc (bool) const
174 return label_text::borrow (m_desc
);
177 /* class statement_event : public checker_event. */
179 /* statement_event's ctor. */
181 statement_event::statement_event (const gimple
*stmt
, tree fndecl
, int depth
,
182 const program_state
&dst_state
)
183 : checker_event (EK_STMT
, gimple_location (stmt
), fndecl
, depth
),
185 m_dst_state (dst_state
)
189 /* Implementation of diagnostic_event::get_desc vfunc for
191 Use the statement's dump form as the event's description. */
194 statement_event::get_desc (bool) const
197 pp_string (&pp
, "stmt: ");
198 pp_gimple_stmt_1 (&pp
, m_stmt
, 0, (dump_flags_t
)0);
199 return label_text::take (xstrdup (pp_formatted_text (&pp
)));
202 /* class function_entry_event : public checker_event. */
204 /* Implementation of diagnostic_event::get_desc vfunc for
205 function_entry_event.
207 Use a string such as "entry to 'foo'" as the event's description. */
210 function_entry_event::get_desc (bool can_colorize
) const
212 return make_label_text (can_colorize
, "entry to %qE", m_fndecl
);
215 /* class state_change_event : public checker_event. */
217 /* state_change_event's ctor. */
219 state_change_event::state_change_event (const supernode
*node
,
222 const state_machine
&sm
,
224 state_machine::state_t from
,
225 state_machine::state_t to
,
226 const svalue
*origin
,
227 const program_state
&dst_state
)
228 : checker_event (EK_STATE_CHANGE
,
229 stmt
->location
, node
->m_fun
->decl
,
231 m_node (node
), m_stmt (stmt
), m_sm (sm
),
232 m_sval (sval
), m_from (from
), m_to (to
),
234 m_dst_state (dst_state
)
238 /* Implementation of diagnostic_event::get_desc vfunc for
241 Attempt to generate a nicer human-readable description.
242 For greatest precision-of-wording, give the pending diagnostic
243 a chance to describe this state change (in terms of the
245 Note that we only have a pending_diagnostic set on the event once
246 the diagnostic is about to being emitted, so the description for
247 an event can change. */
250 state_change_event::get_desc (bool can_colorize
) const
252 if (m_pending_diagnostic
)
254 region_model
*model
= m_dst_state
.m_region_model
;
255 tree var
= model
->get_representative_tree (m_sval
);
256 tree origin
= model
->get_representative_tree (m_origin
);
257 label_text custom_desc
258 = m_pending_diagnostic
->describe_state_change
259 (evdesc::state_change (can_colorize
, var
, origin
,
260 m_from
, m_to
, m_emission_id
, *this));
261 if (custom_desc
.m_buffer
)
263 if (flag_analyzer_verbose_state_changes
)
265 /* Append debug version. */
268 result
= make_label_text
270 "%s (state of %qE: %qs -> %qs, origin: %qE)",
271 custom_desc
.m_buffer
,
277 result
= make_label_text
279 "%s (state of %qE: %qs -> %qs, NULL origin)",
280 custom_desc
.m_buffer
,
284 custom_desc
.maybe_free ();
292 /* Fallback description. */
295 label_text sval_desc
= m_sval
->get_desc ();
298 label_text origin_desc
= m_origin
->get_desc ();
299 return make_label_text
301 "state of %qs: %qs -> %qs (origin: %qs)",
305 origin_desc
.m_buffer
);
308 return make_label_text
310 "state of %qs: %qs -> %qs (NULL origin)",
317 gcc_assert (m_origin
== NULL
);
318 return make_label_text
320 "global state: %qs -> %qs",
326 /* class superedge_event : public checker_event. */
328 /* Get the callgraph_superedge for this superedge_event, which must be
329 for an interprocedural edge, rather than a CFG edge. */
331 const callgraph_superedge
&
332 superedge_event::get_callgraph_superedge () const
334 gcc_assert (m_sedge
->m_kind
!= SUPEREDGE_CFG_EDGE
);
335 return *m_sedge
->dyn_cast_callgraph_superedge ();
338 /* Determine if this event should be filtered at the given verbosity
342 superedge_event::should_filter_p (int verbosity
) const
344 switch (m_sedge
->m_kind
)
346 case SUPEREDGE_CFG_EDGE
:
353 /* Filter events with empty descriptions. This ought to filter
354 FALLTHRU, but retain true/false/switch edges. */
355 label_text desc
= get_desc (false);
356 gcc_assert (desc
.m_buffer
);
357 if (desc
.m_buffer
[0] == '\0')
370 /* superedge_event's ctor. */
372 superedge_event::superedge_event (enum event_kind kind
,
373 const exploded_edge
&eedge
,
374 location_t loc
, tree fndecl
, int depth
)
375 : checker_event (kind
, loc
, fndecl
, depth
),
376 m_eedge (eedge
), m_sedge (eedge
.m_sedge
),
377 m_var (NULL_TREE
), m_critical_state (0)
381 /* class cfg_edge_event : public superedge_event. */
383 /* Get the cfg_superedge for this cfg_edge_event. */
385 const cfg_superedge
&
386 cfg_edge_event::get_cfg_superedge () const
388 return *m_sedge
->dyn_cast_cfg_superedge ();
391 /* cfg_edge_event's ctor. */
393 cfg_edge_event::cfg_edge_event (enum event_kind kind
,
394 const exploded_edge
&eedge
,
395 location_t loc
, tree fndecl
, int depth
)
396 : superedge_event (kind
, eedge
, loc
, fndecl
, depth
)
398 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_CFG_EDGE
);
401 /* class start_cfg_edge_event : public cfg_edge_event. */
403 /* Implementation of diagnostic_event::get_desc vfunc for
404 start_cfg_edge_event.
406 If -fanalyzer-verbose-edges, then generate low-level descriptions, such
408 "taking 'true' edge SN:7 -> SN:8".
410 Otherwise, generate strings using the label of the underlying CFG if
412 "following 'true' branch..." or
413 "following 'case 3' branch..."
414 "following 'default' branch..."
416 For conditionals, attempt to supply a description of the condition that
418 "following 'false' branch (when 'ptr' is non-NULL)..."
420 Failing that, return an empty description (which will lead to this event
424 start_cfg_edge_event::get_desc (bool can_colorize
) const
426 bool user_facing
= !flag_analyzer_verbose_edges
;
427 char *edge_desc
= m_sedge
->get_description (user_facing
);
430 if (edge_desc
&& strlen (edge_desc
) > 0)
432 label_text cond_desc
= maybe_describe_condition (can_colorize
);
434 if (cond_desc
.m_buffer
)
436 result
= make_label_text (can_colorize
,
437 "following %qs branch (%s)...",
438 edge_desc
, cond_desc
.m_buffer
);
439 cond_desc
.maybe_free ();
443 result
= make_label_text (can_colorize
,
444 "following %qs branch...",
453 return label_text::borrow ("");
458 if (strlen (edge_desc
) > 0)
461 = make_label_text (can_colorize
,
462 "taking %qs edge SN:%i -> SN:%i",
464 m_sedge
->m_src
->m_index
,
465 m_sedge
->m_dest
->m_index
);
472 return make_label_text (can_colorize
,
473 "taking edge SN:%i -> SN:%i",
474 m_sedge
->m_src
->m_index
,
475 m_sedge
->m_dest
->m_index
);
480 /* Attempt to generate a description of any condition that holds at this edge.
482 The intent is to make the user-facing messages more clear, especially for
483 cases where there's a single or double-negative, such as
484 when describing the false branch of an inverted condition.
486 For example, rather than printing just:
491 | (1) following 'false' branch...
493 it's clearer to spell out the condition that holds:
498 | (1) following 'false' branch (when 'ptr' is non-NULL)...
499 ^^^^^^^^^^^^^^^^^^^^^^
501 In the above example, this function would generate the highlighted
502 string: "when 'ptr' is non-NULL".
504 If the edge is not a condition, or it's not clear that a description of
505 the condition would be helpful to the user, return NULL. */
508 start_cfg_edge_event::maybe_describe_condition (bool can_colorize
) const
510 const cfg_superedge
& cfg_sedge
= get_cfg_superedge ();
512 if (cfg_sedge
.true_value_p () || cfg_sedge
.false_value_p ())
514 const gimple
*last_stmt
= m_sedge
->m_src
->get_last_stmt ();
515 if (const gcond
*cond_stmt
= dyn_cast
<const gcond
*> (last_stmt
))
517 enum tree_code op
= gimple_cond_code (cond_stmt
);
518 tree lhs
= gimple_cond_lhs (cond_stmt
);
519 tree rhs
= gimple_cond_rhs (cond_stmt
);
520 if (cfg_sedge
.false_value_p ())
521 op
= invert_tree_comparison (op
, false /* honor_nans */);
522 return maybe_describe_condition (can_colorize
,
526 return label_text::borrow (NULL
);
529 /* Subroutine of maybe_describe_condition above.
531 Attempt to generate a user-facing description of the condition
532 LHS OP RHS, but only if it is likely to make it easier for the
533 user to understand a condition. */
536 start_cfg_edge_event::maybe_describe_condition (bool can_colorize
,
541 /* In theory we could just build a tree via
542 fold_build2 (op, boolean_type_node, lhs, rhs)
543 and print it with %qE on it, but this leads to warts such as
544 parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
546 /* Special-case: describe testing the result of strcmp, as figuring
547 out what the "true" or "false" path is can be confusing to the user. */
548 if (TREE_CODE (lhs
) == SSA_NAME
551 if (gcall
*call
= dyn_cast
<gcall
*> (SSA_NAME_DEF_STMT (lhs
)))
552 if (is_special_named_call_p (call
, "strcmp", 2))
555 return label_text::borrow ("when the strings are equal");
557 return label_text::borrow ("when the strings are non-equal");
561 /* Only attempt to generate text for sufficiently simple expressions. */
562 if (!should_print_expr_p (lhs
))
563 return label_text::borrow (NULL
);
564 if (!should_print_expr_p (rhs
))
565 return label_text::borrow (NULL
);
567 /* Special cases for pointer comparisons against NULL. */
568 if (POINTER_TYPE_P (TREE_TYPE (lhs
))
569 && POINTER_TYPE_P (TREE_TYPE (rhs
))
573 return make_label_text (can_colorize
, "when %qE is NULL",
576 return make_label_text (can_colorize
, "when %qE is non-NULL",
580 return make_label_text (can_colorize
, "when %<%E %s %E%>",
581 lhs
, op_symbol_code (op
), rhs
);
584 /* Subroutine of maybe_describe_condition.
586 Return true if EXPR is we will get suitable user-facing output
590 start_cfg_edge_event::should_print_expr_p (tree expr
)
592 if (TREE_CODE (expr
) == SSA_NAME
)
594 if (SSA_NAME_VAR (expr
))
595 return should_print_expr_p (SSA_NAME_VAR (expr
));
603 if (CONSTANT_CLASS_P (expr
))
609 /* class call_event : public superedge_event. */
611 /* call_event's ctor. */
613 call_event::call_event (const exploded_edge
&eedge
,
614 location_t loc
, tree fndecl
, int depth
)
615 : superedge_event (EK_CALL_EDGE
, eedge
, loc
, fndecl
, depth
)
618 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_CALL
);
620 m_src_snode
= eedge
.m_src
->get_supernode ();
621 m_dest_snode
= eedge
.m_dest
->get_supernode ();
624 /* Implementation of diagnostic_event::get_desc vfunc for
627 If this call event passes critical state for an sm-based warning,
628 allow the diagnostic to generate a precise description, such as:
630 "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
632 Otherwise, generate a description of the form
633 "calling 'foo' from 'bar'". */
636 call_event::get_desc (bool can_colorize
) const
638 if (m_critical_state
&& m_pending_diagnostic
)
641 tree var
= fixup_tree_for_diagnostic (m_var
);
642 label_text custom_desc
643 = m_pending_diagnostic
->describe_call_with_state
644 (evdesc::call_with_state (can_colorize
,
645 m_src_snode
->m_fun
->decl
,
646 m_dest_snode
->m_fun
->decl
,
649 if (custom_desc
.m_buffer
)
653 return make_label_text (can_colorize
,
654 "calling %qE from %qE",
655 m_dest_snode
->m_fun
->decl
,
656 m_src_snode
->m_fun
->decl
);
659 /* Override of checker_event::is_call_p for calls. */
662 call_event::is_call_p () const
667 /* class return_event : public superedge_event. */
669 /* return_event's ctor. */
671 return_event::return_event (const exploded_edge
&eedge
,
672 location_t loc
, tree fndecl
, int depth
)
673 : superedge_event (EK_RETURN_EDGE
, eedge
, loc
, fndecl
, depth
)
676 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_RETURN
);
678 m_src_snode
= eedge
.m_src
->get_supernode ();
679 m_dest_snode
= eedge
.m_dest
->get_supernode ();
682 /* Implementation of diagnostic_event::get_desc vfunc for
685 If this return event returns critical state for an sm-based warning,
686 allow the diagnostic to generate a precise description, such as:
688 "possible of NULL to 'foo' from 'bar'"
690 Otherwise, generate a description of the form
691 "returning to 'foo' from 'bar'. */
694 return_event::get_desc (bool can_colorize
) const
696 /* For greatest precision-of-wording, if this is returning the
697 state involved in the pending diagnostic, give the pending
698 diagnostic a chance to describe this return (in terms of
700 if (m_critical_state
&& m_pending_diagnostic
)
702 label_text custom_desc
703 = m_pending_diagnostic
->describe_return_of_state
704 (evdesc::return_of_state (can_colorize
,
705 m_dest_snode
->m_fun
->decl
,
706 m_src_snode
->m_fun
->decl
,
708 if (custom_desc
.m_buffer
)
711 return make_label_text (can_colorize
,
712 "returning to %qE from %qE",
713 m_dest_snode
->m_fun
->decl
,
714 m_src_snode
->m_fun
->decl
);
717 /* Override of checker_event::is_return_p for returns. */
720 return_event::is_return_p () const
725 /* class start_consolidated_cfg_edges_event : public checker_event. */
728 start_consolidated_cfg_edges_event::get_desc (bool can_colorize
) const
730 return make_label_text (can_colorize
,
731 "following %qs branch...",
732 m_edge_sense
? "true" : "false");
735 /* class setjmp_event : public checker_event. */
737 /* Implementation of diagnostic_event::get_desc vfunc for
741 setjmp_event::get_desc (bool can_colorize
) const
743 return make_label_text (can_colorize
,
745 get_user_facing_name (m_setjmp_call
));
748 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
750 Record this setjmp's event ID into the path, so that rewind events can
754 setjmp_event::prepare_for_emission (checker_path
*path
,
755 pending_diagnostic
*pd
,
756 diagnostic_event_id_t emission_id
)
758 checker_event::prepare_for_emission (path
, pd
, emission_id
);
759 path
->record_setjmp_event (m_enode
, emission_id
);
762 /* class rewind_event : public checker_event. */
764 /* Get the fndecl containing the site of the longjmp call. */
767 rewind_event::get_longjmp_caller () const
769 return m_eedge
->m_src
->get_function ()->decl
;
772 /* Get the fndecl containing the site of the setjmp call. */
775 rewind_event::get_setjmp_caller () const
777 return m_eedge
->m_dest
->get_function ()->decl
;
780 /* rewind_event's ctor. */
782 rewind_event::rewind_event (const exploded_edge
*eedge
,
783 enum event_kind kind
,
784 location_t loc
, tree fndecl
, int depth
,
785 const rewind_info_t
*rewind_info
)
786 : checker_event (kind
, loc
, fndecl
, depth
),
787 m_rewind_info (rewind_info
),
790 gcc_assert (m_eedge
->m_custom_info
== m_rewind_info
);
793 /* class rewind_from_longjmp_event : public rewind_event. */
795 /* Implementation of diagnostic_event::get_desc vfunc for
796 rewind_from_longjmp_event. */
799 rewind_from_longjmp_event::get_desc (bool can_colorize
) const
802 = get_user_facing_name (m_rewind_info
->get_longjmp_call ());
804 if (get_longjmp_caller () == get_setjmp_caller ())
805 /* Special-case: purely intraprocedural rewind. */
806 return make_label_text (can_colorize
,
807 "rewinding within %qE from %qs...",
808 get_longjmp_caller (),
811 return make_label_text (can_colorize
,
812 "rewinding from %qs in %qE...",
814 get_longjmp_caller ());
817 /* class rewind_to_setjmp_event : public rewind_event. */
819 /* Implementation of diagnostic_event::get_desc vfunc for
820 rewind_to_setjmp_event. */
823 rewind_to_setjmp_event::get_desc (bool can_colorize
) const
826 = get_user_facing_name (m_rewind_info
->get_setjmp_call ());
828 /* If we can, identify the ID of the setjmp_event. */
829 if (m_original_setjmp_event_id
.known_p ())
831 if (get_longjmp_caller () == get_setjmp_caller ())
832 /* Special-case: purely intraprocedural rewind. */
833 return make_label_text (can_colorize
,
834 "...to %qs (saved at %@)",
836 &m_original_setjmp_event_id
);
838 return make_label_text (can_colorize
,
839 "...to %qs in %qE (saved at %@)",
841 get_setjmp_caller (),
842 &m_original_setjmp_event_id
);
846 if (get_longjmp_caller () == get_setjmp_caller ())
847 /* Special-case: purely intraprocedural rewind. */
848 return make_label_text (can_colorize
,
851 get_setjmp_caller ());
853 return make_label_text (can_colorize
,
856 get_setjmp_caller ());
860 /* Implementation of checker_event::prepare_for_emission vfunc for
861 rewind_to_setjmp_event.
863 Attempt to look up the setjmp event ID that recorded the jmp_buf
867 rewind_to_setjmp_event::prepare_for_emission (checker_path
*path
,
868 pending_diagnostic
*pd
,
869 diagnostic_event_id_t emission_id
)
871 checker_event::prepare_for_emission (path
, pd
, emission_id
);
872 path
->get_setjmp_event (m_rewind_info
->get_enode_origin (),
873 &m_original_setjmp_event_id
);
876 /* class warning_event : public checker_event. */
878 /* Implementation of diagnostic_event::get_desc vfunc for
881 If the pending diagnostic implements describe_final_event, use it,
882 generating a precise description e.g.
883 "second 'free' here; first 'free' was at (7)"
885 Otherwise generate a generic description. */
888 warning_event::get_desc (bool can_colorize
) const
890 if (m_pending_diagnostic
)
892 tree var
= fixup_tree_for_diagnostic (m_var
);
894 = m_pending_diagnostic
->describe_final_event
895 (evdesc::final_event (can_colorize
, var
, m_state
));
896 if (ev_desc
.m_buffer
)
898 if (m_sm
&& flag_analyzer_verbose_state_changes
)
902 result
= make_label_text (can_colorize
,
903 "%s (%qE is in state %qs)",
905 var
, m_state
->get_name ());
907 result
= make_label_text (can_colorize
,
908 "%s (in global state %qs)",
910 m_state
->get_name ());
911 ev_desc
.maybe_free ();
922 return make_label_text (can_colorize
,
923 "here (%qE is in state %qs)",
924 m_var
, m_state
->get_name ());
926 return make_label_text (can_colorize
,
927 "here (in global state %qs)",
928 m_state
->get_name ());
931 return label_text::borrow ("here");
934 /* Print a single-line representation of this path to PP. */
937 checker_path::dump (pretty_printer
*pp
) const
939 pp_character (pp
, '[');
943 FOR_EACH_VEC_ELT (m_events
, i
, e
)
946 pp_string (pp
, ", ");
947 label_text
event_desc (e
->get_desc (false));
948 pp_printf (pp
, "\"%s\"", event_desc
.m_buffer
);
949 event_desc
.maybe_free ();
951 pp_character (pp
, ']');
954 /* Print a multiline form of this path to LOGGER, prefixing it with DESC. */
957 checker_path::maybe_log (logger
*logger
, const char *desc
) const
961 logger
->start_log_line ();
962 logger
->log_partial ("%s: ", desc
);
963 dump (logger
->get_printer ());
964 logger
->end_log_line ();
965 for (unsigned i
= 0; i
< m_events
.length (); i
++)
967 logger
->start_log_line ();
968 logger
->log_partial ("%s[%i]: %s ", desc
, i
,
969 event_kind_to_string (m_events
[i
]->m_kind
));
970 m_events
[i
]->dump (logger
->get_printer ());
971 logger
->end_log_line ();
975 /* Print a multiline form of this path to STDERR. */
978 checker_path::debug () const
982 FOR_EACH_VEC_ELT (m_events
, i
, e
)
984 label_text
event_desc (e
->get_desc (false));
988 event_kind_to_string (m_events
[i
]->m_kind
),
989 event_desc
.m_buffer
);
990 event_desc
.maybe_free ();
994 /* Add a warning_event to the end of this path. */
997 checker_path::add_final_event (const state_machine
*sm
,
998 const exploded_node
*enode
, const gimple
*stmt
,
999 tree var
, state_machine::state_t state
)
1001 checker_event
*end_of_path
1002 = new warning_event (get_stmt_location (stmt
, enode
->get_function ()),
1003 enode
->get_function ()->decl
,
1004 enode
->get_stack_depth (),
1006 add_event (end_of_path
);
1010 checker_path::fixup_locations (pending_diagnostic
*pd
)
1012 for (checker_event
*e
: m_events
)
1013 e
->set_location (pd
->fixup_location (e
->get_location ()));
1016 /* Return true if there is a (start_cfg_edge_event, end_cfg_edge_event) pair
1017 at (IDX, IDX + 1). */
1020 checker_path::cfg_edge_pair_at_p (unsigned idx
) const
1022 if (m_events
.length () < idx
+ 1)
1024 return (m_events
[idx
]->m_kind
== EK_START_CFG_EDGE
1025 && m_events
[idx
+ 1]->m_kind
== EK_END_CFG_EDGE
);
1030 #endif /* #if ENABLE_ANALYZER */