Line data Source code
1 : /* Subclasses of diagnostics::paths::event for analyzer diagnostics.
2 : Copyright (C) 2019-2026 Free Software Foundation, Inc.
3 : Contributed by David Malcolm <dmalcolm@redhat.com>.
4 :
5 : This file is part of GCC.
6 :
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)
10 : any later version.
11 :
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.
16 :
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/>. */
20 :
21 : #include "analyzer/common.h"
22 :
23 : #include "gimple-pretty-print.h"
24 : #include "sbitmap.h"
25 : #include "ordered-hash-map.h"
26 : #include "fold-const.h"
27 : #include "gimple-iterator.h"
28 : #include "inlining-iterator.h"
29 : #include "tree-logical-location.h"
30 : #include "diagnostics/sarif-sink.h"
31 : #include "diagnostics/state-graphs.h"
32 : #include "custom-sarif-properties/state-graphs.h"
33 :
34 : #include "analyzer/analyzer-logging.h"
35 : #include "analyzer/sm.h"
36 : #include "analyzer/call-string.h"
37 : #include "analyzer/program-point.h"
38 : #include "analyzer/store.h"
39 : #include "analyzer/region-model.h"
40 : #include "analyzer/program-state.h"
41 : #include "analyzer/checker-path.h"
42 : #include "analyzer/supergraph.h"
43 : #include "analyzer/pending-diagnostic.h"
44 : #include "analyzer/diagnostic-manager.h"
45 : #include "analyzer/constraint-manager.h"
46 : #include "analyzer/checker-event.h"
47 : #include "analyzer/exploded-graph.h"
48 : #include "analyzer/callsite-expr.h"
49 : #include "analyzer/state-transition.h"
50 :
51 : #if ENABLE_ANALYZER
52 :
53 : namespace ana {
54 :
55 : /* Get a string for EK. */
56 :
57 : const char *
58 192 : event_kind_to_string (enum event_kind ek)
59 : {
60 192 : switch (ek)
61 : {
62 0 : default:
63 0 : gcc_unreachable ();
64 : case event_kind::debug:
65 : return "debug";
66 4 : case event_kind::custom:
67 4 : return "custom";
68 8 : case event_kind::stmt:
69 8 : return "stmt";
70 18 : case event_kind::region_creation:
71 18 : return "region_creation";
72 0 : case event_kind::state_transition:
73 0 : return "state_transition";
74 23 : case event_kind::function_entry:
75 23 : return "function_entry";
76 26 : case event_kind::state_change:
77 26 : return "state_change";
78 19 : case event_kind::start_cfg_edge:
79 19 : return "start_cfg_edge";
80 19 : case event_kind::end_cfg_edge:
81 19 : return "end_cfg_edge";
82 6 : case event_kind::catch_:
83 6 : return "catch";
84 13 : case event_kind::call_:
85 13 : return "call";
86 3 : case event_kind::return_:
87 3 : return "return";
88 0 : case event_kind::start_consolidated_cfg_edges:
89 0 : return "start_consolidated_cfg_edges";
90 0 : case event_kind::end_consolidated_cfg_edges:
91 0 : return "end_consolidated_cfg_edges";
92 1 : case event_kind::inlined_call:
93 1 : return "inlined_call";
94 1 : case event_kind::setjmp_:
95 1 : return "setjmp";
96 1 : case event_kind::rewind_from_longjmp:
97 1 : return "rewind_from_longjmp";
98 1 : case event_kind::rewind_to_setjmp:
99 1 : return "rewind_to_setjmp";
100 6 : case event_kind::throw_:
101 6 : return "throw";
102 3 : case event_kind::unwind:
103 3 : return "unwind";
104 40 : case event_kind::warning:
105 40 : return "warning";
106 : }
107 : }
108 :
109 : /* class checker_event : public diagnostics::paths::event. */
110 :
111 : /* checker_event's ctor. */
112 :
113 37737 : checker_event::checker_event (enum event_kind kind,
114 37737 : const event_loc_info &loc_info)
115 37737 : : m_path (nullptr),
116 37737 : m_kind (kind), m_loc (loc_info.m_loc),
117 37737 : m_original_fndecl (loc_info.m_fndecl),
118 37737 : m_effective_fndecl (loc_info.m_fndecl),
119 37737 : m_original_depth (loc_info.m_depth),
120 37737 : m_effective_depth (loc_info.m_depth),
121 37737 : m_pending_diagnostic (nullptr), m_emission_id (),
122 : m_logical_loc
123 37737 : (tree_logical_location_manager::key_from_tree (loc_info.m_fndecl))
124 : {
125 : /* Update effective fndecl and depth if inlining has been recorded. */
126 37737 : if (flag_analyzer_undo_inlining)
127 : {
128 37725 : inlining_info info (m_loc);
129 37725 : if (info.get_inner_fndecl ())
130 : {
131 30361 : m_effective_fndecl = info.get_inner_fndecl ();
132 30361 : m_effective_depth += info.get_extra_frames ();
133 30361 : m_logical_loc
134 30361 : = tree_logical_location_manager::key_from_tree (m_effective_fndecl);
135 : }
136 : }
137 37737 : }
138 :
139 : /* No-op implementation of diagnostics::paths::event::get_meaning vfunc for
140 : checker_event: checker events have no meaning by default. */
141 :
142 : diagnostics::paths::event::meaning
143 56 : checker_event::get_meaning () const
144 : {
145 56 : return diagnostics::paths::event::meaning ();
146 : }
147 :
148 : /* Implementation of diagnostics::paths::event::maybe_add_sarif_properties
149 : for checker_event. */
150 :
151 : void
152 155 : checker_event::
153 : maybe_add_sarif_properties (diagnostics::sarif_builder &builder,
154 : diagnostics::sarif_object &thread_flow_loc_obj) const
155 : {
156 155 : auto &props = thread_flow_loc_obj.get_or_create_properties ();
157 : #define PROPERTY_PREFIX "gcc/analyzer/checker_event/"
158 310 : props.set (PROPERTY_PREFIX "emission_id",
159 155 : diagnostic_event_id_to_json (m_emission_id));
160 155 : props.set_string (PROPERTY_PREFIX "kind", event_kind_to_string (m_kind));
161 :
162 155 : if (m_original_fndecl != m_effective_fndecl)
163 0 : props.set_logical_location
164 0 : (PROPERTY_PREFIX "original_fndecl",
165 : builder,
166 0 : tree_logical_location_manager::key_from_tree (m_original_fndecl));
167 :
168 155 : if (m_original_depth != m_effective_depth)
169 0 : props.set_integer (PROPERTY_PREFIX "original_depth", m_original_depth);
170 : #undef PROPERTY_PREFIX
171 155 : }
172 :
173 : /* Dump this event to PP (for debugging/logging purposes). */
174 :
175 : void
176 37 : checker_event::dump (pretty_printer *pp) const
177 : {
178 37 : pp_character (pp, '"');
179 37 : print_desc (*pp);
180 37 : pp_printf (pp, "\" (depth %i", m_effective_depth);
181 :
182 37 : if (m_effective_depth != m_original_depth)
183 10 : pp_printf (pp, " corrected from %i",
184 : m_original_depth);
185 37 : if (m_effective_fndecl)
186 : {
187 37 : pp_printf (pp, ", fndecl %qE", m_effective_fndecl);
188 37 : if (m_effective_fndecl != m_original_fndecl)
189 10 : pp_printf (pp, " corrected from %qE", m_original_fndecl);
190 : }
191 37 : pp_printf (pp, ", m_loc=%llx)",
192 37 : (unsigned long long) get_location ());
193 37 : }
194 :
195 : /* Dump this event to stderr (for debugging/logging purposes). */
196 :
197 : DEBUG_FUNCTION void
198 0 : checker_event::debug () const
199 : {
200 0 : tree_dump_pretty_printer pp (stderr);
201 0 : dump (&pp);
202 0 : pp_newline (&pp);
203 0 : }
204 :
205 : /* Hook for being notified when this event has its final id EMISSION_ID
206 : and is about to emitted for PD.
207 :
208 : Base implementation of checker_event::prepare_for_emission vfunc;
209 : subclasses that override this should chain up to it.
210 :
211 : Record PD and EMISSION_ID, and call the print_desc vfunc, so that any
212 : side-effects of the call to print_desc take place before
213 : pending_diagnostic::emit is called.
214 :
215 : For example, state_change_event::print_desc can call
216 : pending_diagnostic::describe_state_change; free_of_non_heap can use this
217 : to tweak the message (TODO: would be neater to simply capture the
218 : pertinent data within the sm-state). */
219 :
220 : void
221 17355 : checker_event::prepare_for_emission (checker_path *path,
222 : pending_diagnostic *pd,
223 : diagnostics::paths::event_id_t emission_id)
224 : {
225 17355 : m_path = path;
226 17355 : m_pending_diagnostic = pd;
227 17355 : m_emission_id = emission_id;
228 :
229 17355 : auto pp = global_dc->clone_printer ();
230 17355 : print_desc (*pp.get ());
231 17355 : }
232 :
233 : std::unique_ptr<diagnostics::digraphs::digraph>
234 28 : checker_event::maybe_make_diagnostic_state_graph (bool debug) const
235 : {
236 28 : const program_state *state = get_program_state ();
237 28 : if (!state)
238 0 : return nullptr;
239 :
240 28 : gcc_assert (m_path);
241 28 : const extrinsic_state &ext_state = m_path->get_ext_state ();
242 :
243 28 : auto result = state->make_diagnostic_state_graph (ext_state);
244 :
245 28 : if (debug)
246 : {
247 27 : pretty_printer pp;
248 27 : text_art::theme *theme = global_dc->get_diagram_theme ();
249 27 : text_art::dump_to_pp (*state, theme, &pp);
250 27 : const json::string_property program_state_property
251 : (custom_sarif_properties::state_graphs::graph::prefix,
252 27 : "analyzer/program_state/");
253 27 : result->set_property (program_state_property,
254 : pp_formatted_text (&pp));
255 27 : }
256 :
257 28 : return result;
258 28 : }
259 :
260 : /* class debug_event : public checker_event. */
261 :
262 : /* Implementation of diagnostics::paths::event::print_desc vfunc for
263 : debug_event.
264 : Use the saved string as the event's description. */
265 :
266 : void
267 0 : debug_event::print_desc (pretty_printer &pp) const
268 : {
269 0 : pp_string (&pp, m_desc);
270 0 : }
271 :
272 : /* class precanned_custom_event : public custom_event. */
273 :
274 : /* Implementation of diagnostics::paths::event::print_desc vfunc for
275 : precanned_custom_event.
276 : Use the saved string as the event's description. */
277 :
278 : void
279 40 : precanned_custom_event::print_desc (pretty_printer &pp) const
280 : {
281 40 : pp_string (&pp, m_desc);
282 40 : }
283 :
284 : /* class statement_event : public checker_event. */
285 :
286 : /* statement_event's ctor. */
287 :
288 13944 : statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
289 13944 : const program_state &dst_state)
290 : : checker_event (event_kind::stmt,
291 13944 : event_loc_info (gimple_location (stmt), fndecl, depth)),
292 13944 : m_stmt (stmt),
293 13944 : m_dst_state (dst_state)
294 : {
295 13944 : }
296 :
297 : /* Implementation of diagnostics::paths::event::print_desc vfunc for
298 : statement_event.
299 : Use the statement's dump form as the event's description. */
300 :
301 : void
302 12 : statement_event::print_desc (pretty_printer &pp) const
303 : {
304 12 : pp_string (&pp, "stmt: ");
305 12 : pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
306 12 : }
307 :
308 : /* class state_transition_event : public checker_event. */
309 :
310 : void
311 132 : state_transition_event::print_desc (pretty_printer &pp) const
312 : {
313 132 : gcc_assert (m_state_trans);
314 132 : switch (m_state_trans->get_kind ())
315 : {
316 0 : default:
317 0 : gcc_unreachable ();
318 90 : case state_transition::kind::origin:
319 90 : {
320 90 : const state_transition_origin &state_trans
321 : = *static_cast <const state_transition_origin *> (m_state_trans);
322 90 : if (m_pending_diagnostic)
323 : {
324 60 : evdesc::origin_of_state evd (state_trans.m_dst_reg_expr);
325 60 : if (m_pending_diagnostic->describe_origin_of_state (pp, evd))
326 44 : return;
327 : }
328 46 : pp_printf (&pp, "value originates here");
329 : }
330 46 : break;
331 :
332 0 : case state_transition::kind::at_call:
333 0 : case state_transition::kind::at_return:
334 : // These should be handled by call_event and return_event
335 0 : gcc_unreachable ();
336 18 : break;
337 :
338 18 : case state_transition::kind::copy:
339 18 : {
340 18 : const state_transition_copy &state_trans
341 : = *static_cast <const state_transition_copy *> (m_state_trans);
342 18 : if (m_pending_diagnostic)
343 : {
344 24 : evdesc::copy_of_state evd (state_trans.m_src_reg_expr,
345 : state_trans.get_src_event_id (),
346 12 : state_trans.m_dst_reg_expr);
347 12 : if (m_pending_diagnostic->describe_copy_of_state (pp, evd))
348 12 : return;
349 : }
350 6 : auto event_id = state_trans.get_src_event_id ();
351 6 : if (event_id.known_p ())
352 0 : pp_printf (&pp, "copying value from %@ from %qE to %qE",
353 : &event_id,
354 0 : state_trans.m_src_reg_expr,
355 0 : state_trans.m_dst_reg_expr);
356 : else
357 6 : pp_printf (&pp, "copying value from %qE to %qE",
358 6 : state_trans.m_src_reg_expr,
359 6 : state_trans.m_dst_reg_expr);
360 : }
361 6 : break;
362 24 : case state_transition::kind::use:
363 24 : {
364 24 : const state_transition_use &state_trans
365 : = *static_cast <const state_transition_use *> (m_state_trans);
366 24 : if (m_pending_diagnostic)
367 : {
368 32 : evdesc::use_of_state evd (state_trans.m_src_reg_expr,
369 16 : state_trans.get_src_event_id ());
370 16 : if (m_pending_diagnostic->describe_use_of_state (pp, evd))
371 16 : return;
372 : }
373 8 : auto event_id = state_trans.get_src_event_id ();
374 8 : if (state_trans.get_src_event_id ().known_p ())
375 0 : pp_printf (&pp, "using value from %@ from %qE",
376 : &event_id,
377 0 : state_trans.m_src_reg_expr);
378 : else
379 8 : pp_printf (&pp, "using value from %qE",
380 8 : state_trans.m_src_reg_expr);
381 : }
382 8 : break;
383 : }
384 : }
385 :
386 : void
387 44 : state_transition_event::
388 : prepare_for_emission (checker_path *path,
389 : pending_diagnostic *pd,
390 : diagnostics::paths::event_id_t emission_id)
391 : {
392 44 : checker_event::prepare_for_emission (path, pd, emission_id);
393 44 : const_cast<state_transition *> (m_state_trans)->m_event_id = emission_id;
394 44 : }
395 :
396 : /* class region_creation_event : public checker_event. */
397 :
398 1579 : region_creation_event::region_creation_event (const event_loc_info &loc_info)
399 1579 : : checker_event (event_kind::region_creation, loc_info)
400 : {
401 1579 : }
402 :
403 : /* The various region_creation_event subclasses' print_desc
404 : implementations. */
405 :
406 : void
407 1212 : region_creation_event_memory_space::print_desc (pretty_printer &pp) const
408 : {
409 1212 : switch (m_mem_space)
410 : {
411 28 : default:
412 28 : pp_string (&pp, "region created here");
413 28 : return;
414 1086 : case MEMSPACE_STACK:
415 1086 : pp_string (&pp, "region created on stack here");
416 1086 : return;
417 98 : case MEMSPACE_HEAP:
418 98 : pp_string (&pp, "region created on heap here");
419 98 : return;
420 : }
421 : }
422 :
423 : void
424 1630 : region_creation_event_capacity::print_desc (pretty_printer &pp) const
425 : {
426 1630 : gcc_assert (m_capacity);
427 1630 : if (TREE_CODE (m_capacity) == INTEGER_CST)
428 : {
429 1434 : unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
430 1434 : return pp_printf_n (&pp,
431 : hwi,
432 : "capacity: %wu byte",
433 : "capacity: %wu bytes",
434 1434 : hwi);
435 : }
436 : else
437 196 : return pp_printf (&pp, "capacity: %qE bytes", m_capacity);
438 : }
439 :
440 : void
441 214 : region_creation_event_allocation_size::print_desc (pretty_printer &pp) const
442 : {
443 214 : if (m_capacity)
444 : {
445 206 : if (TREE_CODE (m_capacity) == INTEGER_CST)
446 118 : pp_printf_n (&pp,
447 : tree_to_uhwi (m_capacity),
448 : "allocated %E byte here",
449 : "allocated %E bytes here",
450 : m_capacity);
451 : else
452 88 : pp_printf (&pp,
453 : "allocated %qE bytes here",
454 : m_capacity);
455 : }
456 : else
457 8 : pp_printf (&pp, "allocated here");
458 214 : }
459 :
460 : void
461 0 : region_creation_event_debug::print_desc (pretty_printer &pp) const
462 : {
463 0 : pp_string (&pp, "region creation: ");
464 0 : m_reg->dump_to_pp (&pp, true);
465 0 : if (m_capacity)
466 0 : pp_printf (&pp, " capacity: %qE", m_capacity);
467 0 : }
468 :
469 : /* class function_entry_event : public checker_event. */
470 :
471 : /* Implementation of diagnostics::paths::event::print_desc vfunc for
472 : function_entry_event.
473 :
474 : Use a string such as "entry to 'foo'" as the event's description. */
475 :
476 : void
477 2847 : function_entry_event::print_desc (pretty_printer &pp) const
478 : {
479 2847 : if (m_state_trans)
480 : {
481 42 : callsite_expr expr = m_state_trans->get_callsite_expr ();
482 42 : if (tree parm = expr.get_param_tree (m_effective_fndecl))
483 : {
484 40 : auto src_event_id = m_state_trans->get_src_event_id ();
485 40 : if (src_event_id.known_p ())
486 16 : pp_printf (&pp,
487 : "entry to %qE with problematic value from %@ for %qE",
488 16 : m_effective_fndecl,
489 : &src_event_id,
490 : parm);
491 : else
492 24 : pp_printf (&pp, "entry to %qE with problematic value for %qE",
493 24 : m_effective_fndecl, parm);
494 40 : return;
495 : }
496 : }
497 :
498 2807 : pp_printf (&pp, "entry to %qE", m_effective_fndecl);
499 : }
500 :
501 : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
502 : function entry. */
503 :
504 : diagnostics::paths::event::meaning
505 220 : function_entry_event::get_meaning () const
506 : {
507 220 : return meaning (verb::enter, noun::function);
508 : }
509 :
510 : void
511 1715 : function_entry_event::
512 : prepare_for_emission (checker_path *path,
513 : pending_diagnostic *pd,
514 : diagnostics::paths::event_id_t emission_id)
515 : {
516 1715 : checker_event::prepare_for_emission (path, pd, emission_id);
517 1715 : if (m_state_trans)
518 23 : const_cast<state_transition_at_call *> (m_state_trans)->m_event_id = emission_id;
519 1715 : }
520 :
521 : /* class state_change_event : public checker_event. */
522 :
523 : /* state_change_event's ctor. */
524 :
525 3827 : state_change_event::state_change_event (const event_loc_info &loc_info,
526 : const gimple *stmt,
527 : const state_machine &sm,
528 : const svalue *sval,
529 : state_machine::state_t from,
530 : state_machine::state_t to,
531 : const svalue *origin,
532 : const program_state &dst_state,
533 3827 : const exploded_node *enode)
534 : : checker_event (event_kind::state_change, loc_info),
535 3827 : m_stmt (stmt),
536 3827 : m_sm (sm),
537 3827 : m_sval (sval), m_from (from), m_to (to),
538 3827 : m_origin (origin),
539 3827 : m_dst_state (dst_state),
540 3827 : m_enode (enode)
541 : {
542 3827 : }
543 :
544 : /* Implementation of diagnostics::paths::event::print_desc vfunc for
545 : state_change_event.
546 :
547 : Attempt to generate a nicer human-readable description.
548 : For greatest precision-of-wording, give the pending diagnostic
549 : a chance to describe this state change (in terms of the
550 : diagnostic).
551 : Note that we only have a pending_diagnostic set on the event once
552 : the diagnostic is about to being emitted, so the description for
553 : an event can change. */
554 :
555 : void
556 4309 : state_change_event::print_desc (pretty_printer &pp) const
557 : {
558 4309 : if (m_pending_diagnostic)
559 : {
560 4309 : region_model *model = m_dst_state.m_region_model;
561 4309 : tree var = model->get_representative_tree (m_sval);
562 4309 : tree origin = model->get_representative_tree (m_origin);
563 4309 : evdesc::state_change evd (var, origin,
564 4309 : m_from, m_to, m_emission_id, *this);
565 4309 : if (m_pending_diagnostic->describe_state_change (pp, evd))
566 : {
567 4303 : if (flag_analyzer_verbose_state_changes)
568 : {
569 : /* Append debugging information about this event. */
570 :
571 144 : if (var)
572 136 : pp_printf (&pp, " (state of %qE: ", var);
573 : else
574 8 : pp_string (&pp, " (state: ");
575 :
576 144 : pp_printf (&pp, "%qs -> %qs, ",
577 144 : m_from->get_name (),
578 144 : m_to->get_name ());
579 :
580 144 : if (m_origin)
581 0 : pp_printf (&pp, "origin: %qE", origin);
582 : else
583 144 : pp_string (&pp, "NULL origin");
584 :
585 : /* Get any "meaning" of event. */
586 144 : diagnostics::paths::event::meaning meaning = get_meaning ();
587 144 : pp_string (&pp, ", meaning: ");
588 144 : meaning.dump_to_pp (&pp);
589 144 : pp_string (&pp, ")");
590 : }
591 4303 : return;
592 : }
593 : }
594 :
595 : /* Fallback description. */
596 6 : if (m_sval)
597 : {
598 6 : label_text sval_desc = m_sval->get_desc ();
599 6 : pp_printf (&pp,
600 : "state of %qs: %qs -> %qs",
601 : sval_desc.get (),
602 6 : m_from->get_name (),
603 6 : m_to->get_name ());
604 6 : if (m_origin)
605 : {
606 0 : label_text origin_desc = m_origin->get_desc ();
607 0 : pp_printf (&pp, " (origin: %qs)",
608 : origin_desc.get ());
609 0 : }
610 : else
611 6 : pp_string (&pp, " (NULL origin)");
612 6 : }
613 : else
614 : {
615 0 : gcc_assert (m_origin == nullptr);
616 0 : pp_printf (&pp,
617 : "global state: %qs -> %qs",
618 0 : m_from->get_name (),
619 0 : m_to->get_name ());
620 : }
621 : }
622 :
623 : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
624 : state change events: delegate to the pending_diagnostic to
625 : get any meaning. */
626 :
627 : diagnostics::paths::event::meaning
628 336 : state_change_event::get_meaning () const
629 : {
630 336 : if (m_pending_diagnostic)
631 : {
632 336 : region_model *model = m_dst_state.m_region_model;
633 336 : tree var = model->get_representative_tree (m_sval);
634 336 : tree origin = model->get_representative_tree (m_origin);
635 336 : evdesc::state_change evd (var, origin,
636 336 : m_from, m_to, m_emission_id, *this);
637 336 : return m_pending_diagnostic->get_meaning_for_state_change (evd);
638 : }
639 : else
640 0 : return meaning ();
641 : }
642 :
643 : /* class superedge_event : public checker_event. */
644 :
645 : /* Implementation of diagnostics::paths::event::maybe_add_sarif_properties
646 : for superedge_event. */
647 :
648 : void
649 49 : superedge_event::
650 : maybe_add_sarif_properties (diagnostics::sarif_builder &builder,
651 : diagnostics::sarif_object &thread_flow_loc_obj)
652 : const
653 : {
654 49 : checker_event::maybe_add_sarif_properties (builder, thread_flow_loc_obj);
655 49 : auto &props = thread_flow_loc_obj.get_or_create_properties ();
656 : #define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
657 49 : if (m_sedge)
658 49 : props.set (PROPERTY_PREFIX "superedge", m_sedge->to_json ());
659 : #undef PROPERTY_PREFIX
660 49 : }
661 :
662 : /* Determine if this event should be filtered at the given verbosity
663 : level. */
664 :
665 : bool
666 2690 : superedge_event::should_filter_p (int verbosity) const
667 : {
668 2690 : if (m_sedge->get_any_cfg_edge ())
669 : {
670 2690 : if (verbosity < 2)
671 : return true;
672 :
673 2657 : if (verbosity < 4)
674 : {
675 : /* Filter events with empty descriptions. This ought to filter
676 : FALLTHRU, but retain true/false/switch edges. */
677 2657 : auto pp = global_dc->clone_printer ();
678 2657 : print_desc (*pp.get ());
679 2657 : if (pp_formatted_text (pp.get ()) [0] == '\0')
680 3 : return true;
681 2657 : }
682 : }
683 : return false;
684 : }
685 :
686 : const program_state *
687 12 : superedge_event::get_program_state () const
688 : {
689 12 : return &m_eedge.m_dest->get_state ();
690 : }
691 :
692 : const call_and_return_op *
693 1241 : superedge_event::get_call_and_return_op () const
694 : {
695 1241 : if (m_sedge)
696 1241 : if (auto base_op = m_sedge->get_op ())
697 1241 : return base_op->dyn_cast_call_and_return_op ();
698 : return nullptr;
699 : }
700 :
701 : /* superedge_event's ctor. */
702 :
703 7017 : superedge_event::superedge_event (enum event_kind kind,
704 : const exploded_edge &eedge,
705 7017 : const event_loc_info &loc_info)
706 : : checker_event (kind, loc_info),
707 7017 : m_eedge (eedge), m_sedge (eedge.m_sedge)
708 : {
709 7017 : gcc_assert (m_sedge);
710 7017 : }
711 :
712 : /* class cfg_edge_event : public superedge_event. */
713 :
714 : /* cfg_edge_event's ctor. */
715 :
716 5776 : cfg_edge_event::cfg_edge_event (enum event_kind kind,
717 : const exploded_edge &eedge,
718 : const event_loc_info &loc_info,
719 5776 : const control_flow_op *op)
720 : : superedge_event (kind, eedge, loc_info),
721 5776 : m_op (op)
722 : {
723 5776 : }
724 :
725 : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
726 : CFG edge events. */
727 :
728 : diagnostics::paths::event::meaning
729 292 : cfg_edge_event::get_meaning () const
730 : {
731 292 : if (::edge e = get_cfg_edge ())
732 : {
733 292 : if (e->flags & EDGE_TRUE_VALUE)
734 124 : return meaning (verb::branch, property::true_);
735 168 : else if (e->flags & EDGE_FALSE_VALUE)
736 128 : return meaning (verb::branch, property::false_);
737 : }
738 40 : return meaning ();
739 : }
740 :
741 : ::edge
742 825 : cfg_edge_event::get_cfg_edge () const
743 : {
744 825 : return m_sedge->get_any_cfg_edge ();
745 : }
746 :
747 : /* If this event is for a conditional, write the sense of the
748 : conditional to *OUT and return true.
749 : Otherwise return false. */
750 :
751 : bool
752 533 : cfg_edge_event::maybe_get_edge_sense (bool *out) const
753 : {
754 533 : if (::edge e = get_cfg_edge ())
755 : {
756 533 : if (e->flags & EDGE_TRUE_VALUE)
757 : {
758 263 : *out = true;
759 263 : return true;
760 : }
761 270 : else if (e->flags & EDGE_FALSE_VALUE)
762 : {
763 267 : *out = false;
764 267 : return true;
765 : }
766 : }
767 : return false;
768 : }
769 :
770 : /* class start_cfg_edge_event : public cfg_edge_event. */
771 :
772 : /* Implementation of diagnostics::paths::event::print_desc vfunc for
773 : start_cfg_edge_event.
774 :
775 : If -fanalyzer-verbose-edges, then generate low-level descriptions, such
776 : as
777 : "taking 'true' edge SN:7 -> SN:8".
778 :
779 : Otherwise, generate strings using the label of the underlying CFG if
780 : any, such as:
781 : "following 'true' branch..." or
782 : "following 'case 3' branch..."
783 : "following 'default' branch..."
784 :
785 : For conditionals, attempt to supply a description of the condition that
786 : holds, such as:
787 : "following 'false' branch (when 'ptr' is non-NULL)..."
788 :
789 : Failing that, print nothing (which will lead to this event
790 : being filtered). */
791 :
792 : void
793 7307 : start_cfg_edge_event::print_desc (pretty_printer &pp) const
794 : {
795 7307 : bool user_facing = !flag_analyzer_verbose_edges;
796 7307 : label_text edge_desc (m_sedge->get_description (user_facing));
797 7307 : if (user_facing)
798 : {
799 7307 : if (edge_desc.get ()
800 7307 : && strlen (edge_desc.get ()) > 0
801 14611 : && m_op)
802 : {
803 7304 : label_text cond_desc
804 7304 : = m_op->maybe_describe_condition (pp_show_color (&pp));
805 7304 : label_text result;
806 7304 : if (cond_desc.get ())
807 4128 : pp_printf (&pp,
808 : "following %qs branch (%s)...",
809 : edge_desc.get (), cond_desc.get ());
810 : else
811 3176 : pp_printf (&pp,
812 : "following %qs branch...",
813 : edge_desc.get ());
814 11312 : }
815 : }
816 : else
817 : {
818 0 : if (strlen (edge_desc.get ()) > 0)
819 0 : return pp_printf (&pp,
820 : "taking %qs edge SN:%i -> SN:%i",
821 : edge_desc.get (),
822 0 : m_sedge->m_src->m_id,
823 0 : m_sedge->m_dest->m_id);
824 : else
825 0 : return pp_printf (&pp,
826 : "taking edge SN:%i -> SN:%i",
827 0 : m_sedge->m_src->m_id,
828 0 : m_sedge->m_dest->m_id);
829 : }
830 7307 : }
831 :
832 : /* class catch_cfg_edge_event : public cfg_edge_event. */
833 :
834 : diagnostics::paths::event::meaning
835 6 : catch_cfg_edge_event::get_meaning () const
836 : {
837 6 : return meaning (verb::catch_);
838 : }
839 :
840 : /* class call_event : public superedge_event. */
841 :
842 : /* call_event's ctor. */
843 :
844 1241 : call_event::call_event (const exploded_edge &eedge,
845 : const event_loc_info &loc_info,
846 1241 : const state_transition_at_call *state_trans)
847 : : superedge_event (event_kind::call_, eedge, loc_info),
848 1241 : m_state_trans (state_trans)
849 : {
850 1241 : m_src_snode = eedge.m_src->get_supernode ();
851 1241 : m_dest_snode = eedge.m_dest->get_supernode ();
852 1241 : }
853 :
854 : /* Implementation of diagnostics::paths::event::print_desc vfunc for
855 : call_event.
856 :
857 : If this call event passes critical state for an sm-based warning,
858 : allow the diagnostic to generate a precise description, such as:
859 :
860 : "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
861 :
862 : Otherwise, generate a description of the form
863 : "calling 'foo' from 'bar'". */
864 :
865 : void
866 1777 : call_event::print_desc (pretty_printer &pp) const
867 : {
868 1777 : if (m_pending_diagnostic)
869 : {
870 1777 : if (m_critical_state.m_state)
871 : {
872 394 : gcc_assert (m_critical_state.m_var);
873 394 : tree var = fixup_tree_for_diagnostic (m_critical_state.m_var);
874 394 : evdesc::call_with_state evd (m_src_snode->m_fun->decl,
875 394 : m_dest_snode->m_fun->decl,
876 : var,
877 394 : m_critical_state.m_state,
878 394 : m_state_trans);
879 394 : if (m_pending_diagnostic->describe_call_with_state (pp, evd))
880 180 : return;
881 : }
882 1383 : else if (m_state_trans)
883 : {
884 46 : evdesc::call_with_state evd (m_src_snode->m_fun->decl,
885 46 : m_dest_snode->m_fun->decl,
886 : NULL_TREE, nullptr,
887 46 : m_state_trans);
888 46 : if (m_pending_diagnostic->describe_call_with_state (pp, evd))
889 44 : return;
890 42 : callsite_expr expr = m_state_trans->get_callsite_expr ();
891 42 : if (expr.param_p ())
892 : {
893 40 : auto src_event_id = m_state_trans->get_src_event_id ();
894 40 : if (src_event_id.known_p ())
895 16 : pp_printf (&pp,
896 : "passing problematic value from %@ from %qE to %qE"
897 : " via parameter %i",
898 : &src_event_id,
899 : get_caller_fndecl (),
900 : get_callee_fndecl (),
901 : expr.param_num ());
902 : else
903 24 : pp_printf (&pp,
904 : "passing problematic value from %qE to %qE"
905 : " via parameter %i",
906 : get_caller_fndecl (),
907 : get_callee_fndecl (),
908 : expr.param_num ());
909 40 : return;
910 : }
911 : }
912 : }
913 :
914 1553 : pp_printf (&pp,
915 : "calling %qE from %qE",
916 : get_callee_fndecl (),
917 : get_caller_fndecl ());
918 : }
919 :
920 : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
921 : function call events. */
922 :
923 : diagnostics::paths::event::meaning
924 136 : call_event::get_meaning () const
925 : {
926 136 : return meaning (verb::call, noun::function);
927 : }
928 :
929 : /* Override of checker_event::is_call_p for calls. */
930 :
931 : bool
932 2004 : call_event::is_call_p () const
933 : {
934 2004 : return true;
935 : }
936 :
937 : tree
938 1661 : call_event::get_caller_fndecl () const
939 : {
940 1661 : return m_src_snode->m_fun->decl;
941 : }
942 :
943 : tree
944 1661 : call_event::get_callee_fndecl () const
945 : {
946 1661 : return m_dest_snode->m_fun->decl;
947 : }
948 :
949 : const program_state *
950 3 : call_event::get_program_state () const
951 : {
952 : /* Use the state at the source (at the caller),
953 : rather than the one at the dest, which has a frame for the callee. */
954 3 : return &m_eedge.m_src->get_state ();
955 : }
956 :
957 : void
958 920 : call_event::prepare_for_emission (checker_path *path,
959 : pending_diagnostic *pd,
960 : diagnostics::paths::event_id_t emission_id)
961 : {
962 920 : checker_event::prepare_for_emission (path, pd, emission_id);
963 920 : if (m_state_trans)
964 23 : const_cast<state_transition_at_call *> (m_state_trans)->m_event_id = emission_id;
965 920 : }
966 :
967 : /* class return_event : public checker_event. */
968 :
969 : /* return_event's ctor. */
970 :
971 631 : return_event::return_event (const exploded_edge &eedge,
972 : const event_loc_info &loc_info,
973 631 : const state_transition_at_return *state_trans)
974 : : checker_event (event_kind::return_, loc_info),
975 631 : m_eedge (eedge),
976 631 : m_state_trans (state_trans)
977 : {
978 631 : m_src_snode = eedge.m_src->get_supernode ();
979 631 : m_dest_snode = eedge.m_dest->get_supernode ();
980 631 : m_call_and_return_op
981 631 : = eedge.m_src->get_point ().get_call_string ().get_top_of_stack ().m_call_op;
982 631 : }
983 :
984 : /* Implementation of diagnostics::paths::event::print_desc vfunc for
985 : return_event.
986 :
987 : If this return event returns critical state for an sm-based warning,
988 : allow the diagnostic to generate a precise description, such as:
989 :
990 : "possible of NULL to 'foo' from 'bar'"
991 :
992 : Otherwise, generate a description of the form
993 : "returning to 'foo' from 'bar'. */
994 :
995 : void
996 610 : return_event::print_desc (pretty_printer &pp) const
997 : {
998 : /* For greatest precision-of-wording, if this is returning the
999 : state involved in the pending diagnostic, give the pending
1000 : diagnostic a chance to describe this return (in terms of
1001 : itself). */
1002 610 : if (m_pending_diagnostic)
1003 : {
1004 610 : if (m_critical_state.m_state)
1005 : {
1006 133 : evdesc::return_of_state evd (m_dest_snode->m_fun->decl,
1007 133 : m_src_snode->m_fun->decl,
1008 : m_critical_state.m_state,
1009 133 : nullptr);
1010 133 : if (m_pending_diagnostic->describe_return_of_state (pp, evd))
1011 50 : return;
1012 : }
1013 477 : else if (m_state_trans)
1014 : {
1015 24 : evdesc::return_of_state evd (m_dest_snode->m_fun->decl,
1016 24 : m_src_snode->m_fun->decl,
1017 : nullptr,
1018 24 : m_state_trans);
1019 24 : if (m_pending_diagnostic->describe_return_of_state (pp, evd))
1020 24 : return;
1021 : }
1022 : }
1023 :
1024 536 : pp_printf (&pp,
1025 : "returning to %qE from %qE",
1026 536 : m_dest_snode->m_fun->decl,
1027 536 : m_src_snode->m_fun->decl);
1028 : }
1029 :
1030 : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
1031 : function return events. */
1032 :
1033 : diagnostics::paths::event::meaning
1034 54 : return_event::get_meaning () const
1035 : {
1036 54 : return meaning (verb::return_, noun::function);
1037 : }
1038 :
1039 : /* Override of checker_event::is_return_p for returns. */
1040 :
1041 : bool
1042 631 : return_event::is_return_p () const
1043 : {
1044 631 : return true;
1045 : }
1046 :
1047 : const program_state *
1048 3 : return_event::get_program_state () const
1049 : {
1050 3 : return &m_eedge.m_dest->get_state ();
1051 : }
1052 :
1053 : void
1054 310 : return_event::prepare_for_emission (checker_path *path,
1055 : pending_diagnostic *pd,
1056 : diagnostics::paths::event_id_t emission_id)
1057 : {
1058 310 : checker_event::prepare_for_emission (path, pd, emission_id);
1059 310 : if (m_state_trans)
1060 12 : const_cast<state_transition_at_return *> (m_state_trans)->m_event_id = emission_id;
1061 310 : }
1062 :
1063 : /* class start_consolidated_cfg_edges_event : public checker_event. */
1064 :
1065 : void
1066 206 : start_consolidated_cfg_edges_event::print_desc (pretty_printer &pp) const
1067 : {
1068 206 : pp_printf (&pp,
1069 : "following %qs branch...",
1070 206 : m_edge_sense ? "true" : "false");
1071 206 : }
1072 :
1073 : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
1074 : start_consolidated_cfg_edges_event. */
1075 :
1076 : diagnostics::paths::event::meaning
1077 0 : start_consolidated_cfg_edges_event::get_meaning () const
1078 : {
1079 0 : return meaning (verb::branch,
1080 0 : (m_edge_sense ? property::true_ : property::false_));
1081 : }
1082 :
1083 : /* class inlined_call_event : public checker_event. */
1084 :
1085 : void
1086 326 : inlined_call_event::print_desc (pretty_printer &pp) const
1087 : {
1088 326 : pp_printf (&pp,
1089 : "inlined call to %qE from %qE",
1090 326 : m_apparent_callee_fndecl,
1091 326 : m_apparent_caller_fndecl);
1092 326 : }
1093 :
1094 : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
1095 : reconstructed inlined function calls. */
1096 :
1097 : diagnostics::paths::event::meaning
1098 72 : inlined_call_event::get_meaning () const
1099 : {
1100 72 : return meaning (verb::call, noun::function);
1101 : }
1102 :
1103 : /* class setjmp_event : public checker_event. */
1104 :
1105 : /* Implementation of diagnostics::paths::event::print_desc vfunc for
1106 : setjmp_event. */
1107 :
1108 : void
1109 41 : setjmp_event::print_desc (pretty_printer &pp) const
1110 : {
1111 41 : pp_printf (&pp,
1112 : "%qs called here",
1113 : get_user_facing_name (m_setjmp_call));
1114 41 : }
1115 :
1116 : diagnostics::paths::event::meaning
1117 17 : setjmp_event::get_meaning () const
1118 : {
1119 17 : return meaning (verb::setjmp_);
1120 : }
1121 :
1122 : /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1123 :
1124 : Record this setjmp's event ID into the path, so that rewind events can
1125 : use it. */
1126 :
1127 : void
1128 20 : setjmp_event::prepare_for_emission (checker_path *path,
1129 : pending_diagnostic *pd,
1130 : diagnostics::paths::event_id_t emission_id)
1131 : {
1132 20 : checker_event::prepare_for_emission (path, pd, emission_id);
1133 20 : path->record_setjmp_event (m_enode, emission_id);
1134 20 : }
1135 :
1136 : /* class rewind_event : public checker_event. */
1137 :
1138 : /* Get the fndecl containing the site of the longjmp call. */
1139 :
1140 : tree
1141 93 : rewind_event::get_longjmp_caller () const
1142 : {
1143 93 : return m_eedge->m_src->get_function ()->decl;
1144 : }
1145 :
1146 : /* Get the fndecl containing the site of the setjmp call. */
1147 :
1148 : tree
1149 85 : rewind_event::get_setjmp_caller () const
1150 : {
1151 85 : return m_eedge->m_dest->get_function ()->decl;
1152 : }
1153 :
1154 : diagnostics::paths::event::meaning
1155 26 : rewind_event::get_meaning () const
1156 : {
1157 26 : return meaning (verb::longjmp_);
1158 : }
1159 :
1160 : /* rewind_event's ctor. */
1161 :
1162 30 : rewind_event::rewind_event (const exploded_edge *eedge,
1163 : enum event_kind kind,
1164 : const event_loc_info &loc_info,
1165 30 : const rewind_info_t *rewind_info)
1166 : : checker_event (kind, loc_info),
1167 30 : m_rewind_info (rewind_info),
1168 30 : m_eedge (eedge)
1169 : {
1170 30 : gcc_assert (m_eedge->m_custom_info.get () == m_rewind_info);
1171 30 : }
1172 :
1173 : /* class rewind_from_longjmp_event : public rewind_event. */
1174 :
1175 : /* Implementation of diagnostics::paths::event::print_desc vfunc for
1176 : rewind_from_longjmp_event. */
1177 :
1178 : void
1179 31 : rewind_from_longjmp_event::print_desc (pretty_printer &pp) const
1180 : {
1181 31 : const char *src_name
1182 31 : = get_user_facing_name (m_rewind_info->get_longjmp_call ());
1183 :
1184 31 : if (get_longjmp_caller () == get_setjmp_caller ())
1185 : /* Special-case: purely intraprocedural rewind. */
1186 8 : pp_printf (&pp,
1187 : "rewinding within %qE from %qs...",
1188 : get_longjmp_caller (),
1189 : src_name);
1190 : else
1191 23 : pp_printf (&pp,
1192 : "rewinding from %qs in %qE...",
1193 : src_name,
1194 : get_longjmp_caller ());
1195 31 : }
1196 :
1197 : /* class rewind_to_setjmp_event : public rewind_event. */
1198 :
1199 : /* Implementation of diagnostics::paths::event::print_desc vfunc for
1200 : rewind_to_setjmp_event. */
1201 :
1202 : void
1203 31 : rewind_to_setjmp_event::print_desc (pretty_printer &pp) const
1204 : {
1205 31 : const char *dst_name
1206 31 : = get_user_facing_name (m_rewind_info->get_setjmp_call ());
1207 :
1208 : /* If we can, identify the ID of the setjmp_event. */
1209 31 : if (m_original_setjmp_event_id.known_p ())
1210 : {
1211 16 : if (get_longjmp_caller () == get_setjmp_caller ())
1212 : /* Special-case: purely intraprocedural rewind. */
1213 4 : pp_printf (&pp,
1214 : "...to %qs (saved at %@)",
1215 : dst_name,
1216 : &m_original_setjmp_event_id);
1217 : else
1218 12 : pp_printf (&pp,
1219 : "...to %qs in %qE (saved at %@)",
1220 : dst_name,
1221 : get_setjmp_caller (),
1222 : &m_original_setjmp_event_id);
1223 : }
1224 : else
1225 : {
1226 15 : if (get_longjmp_caller () == get_setjmp_caller ())
1227 : /* Special-case: purely intraprocedural rewind. */
1228 4 : pp_printf (&pp,
1229 : "...to %qs",
1230 : dst_name);
1231 : else
1232 11 : pp_printf (&pp,
1233 : "...to %qs in %qE",
1234 : dst_name,
1235 : get_setjmp_caller ());
1236 : }
1237 31 : }
1238 :
1239 : /* Implementation of checker_event::prepare_for_emission vfunc for
1240 : rewind_to_setjmp_event.
1241 :
1242 : Attempt to look up the setjmp event ID that recorded the jmp_buf
1243 : for this rewind. */
1244 :
1245 : void
1246 15 : rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
1247 : pending_diagnostic *pd,
1248 : diagnostics::paths::event_id_t emission_id)
1249 : {
1250 15 : checker_event::prepare_for_emission (path, pd, emission_id);
1251 15 : path->get_setjmp_event (m_rewind_info->get_enode_origin (),
1252 : &m_original_setjmp_event_id);
1253 15 : }
1254 :
1255 : /* class throw_event : public checker_event. */
1256 :
1257 : diagnostics::paths::event::meaning
1258 6 : throw_event::get_meaning () const
1259 : {
1260 6 : return meaning (verb::throw_);
1261 : }
1262 :
1263 : /* class explicit_throw_event : public throw_event. */
1264 : void
1265 150 : explicit_throw_event::print_desc (pretty_printer &pp) const
1266 : {
1267 150 : if (m_is_rethrow)
1268 : {
1269 30 : if (m_type)
1270 18 : pp_printf (&pp, "rethrowing exception of type %qT here...", m_type);
1271 : else
1272 12 : pp_printf (&pp, "rethrowing exception here...");
1273 : }
1274 : else
1275 : {
1276 120 : if (m_type)
1277 120 : pp_printf (&pp, "throwing exception of type %qT here...", m_type);
1278 : else
1279 0 : pp_printf (&pp, "throwing exception here...");
1280 : }
1281 150 : }
1282 :
1283 : /* class throw_from_call_to_external_fn_event : public throw_event. */
1284 :
1285 : void
1286 52 : throw_from_call_to_external_fn_event::print_desc (pretty_printer &pp) const
1287 : {
1288 52 : if (m_fndecl)
1289 52 : pp_printf (&pp, "if %qD throws an exception...", m_fndecl);
1290 : else
1291 0 : pp_printf (&pp, "if the called function throws an exception...");
1292 52 : }
1293 :
1294 : // class unwind_event : public checker_event
1295 :
1296 : void
1297 26 : unwind_event::print_desc (pretty_printer &pp) const
1298 : {
1299 26 : if (m_num_frames > 1)
1300 18 : pp_printf (&pp, "unwinding %i stack frames", m_num_frames);
1301 : else
1302 8 : pp_printf (&pp, "unwinding stack frame");
1303 26 : }
1304 :
1305 : diagnostics::paths::event::meaning
1306 3 : unwind_event::get_meaning () const
1307 : {
1308 3 : return meaning (verb::unwind_);
1309 : }
1310 :
1311 : /* class warning_event : public checker_event. */
1312 :
1313 : /* Implementation of diagnostics::paths::event::print_desc vfunc for
1314 : warning_event.
1315 :
1316 : If the pending diagnostic implements describe_final_event, use it,
1317 : generating a precise description e.g.
1318 : "second 'free' here; first 'free' was at (7)"
1319 :
1320 : Otherwise generate a generic description. */
1321 :
1322 : void
1323 8292 : warning_event::print_desc (pretty_printer &pp) const
1324 : {
1325 8292 : if (m_pending_diagnostic)
1326 : {
1327 8280 : tree var = fixup_tree_for_diagnostic (m_var);
1328 8280 : evdesc::final_event evd (var, m_state, *this);
1329 8280 : if (m_pending_diagnostic->describe_final_event (pp, evd))
1330 : {
1331 7661 : if (m_sm && flag_analyzer_verbose_state_changes)
1332 : {
1333 72 : if (var)
1334 64 : pp_printf (&pp, " (%qE is in state %qs)",
1335 64 : var, m_state->get_name ());
1336 : else
1337 8 : pp_printf (&pp, " (in global state %qs)",
1338 8 : m_state->get_name ());
1339 : }
1340 7661 : return;
1341 : }
1342 : }
1343 :
1344 631 : if (m_sm)
1345 : {
1346 64 : if (m_var)
1347 64 : pp_printf (&pp, "here (%qE is in state %qs)",
1348 64 : m_var, m_state->get_name ());
1349 : else
1350 0 : pp_printf (&pp, "here (in global state %qs)",
1351 0 : m_state->get_name ());
1352 64 : return;
1353 : }
1354 : else
1355 567 : pp_string (&pp, "here");
1356 : }
1357 :
1358 : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
1359 : warning_event. */
1360 :
1361 : diagnostics::paths::event::meaning
1362 232 : warning_event::get_meaning () const
1363 : {
1364 232 : return meaning (verb::danger, noun::unknown);
1365 : }
1366 :
1367 : const program_state *
1368 3 : warning_event::get_program_state () const
1369 : {
1370 3 : if (m_program_state)
1371 : return m_program_state.get ();
1372 : else
1373 1 : return &m_enode->get_state ();
1374 : }
1375 :
1376 : } // namespace ana
1377 :
1378 : #endif /* #if ENABLE_ANALYZER */
|