98f1053da8fcac42d8a47373c585af284d1cdcce
[platform/upstream/gcc.git] / gcc / analyzer / checker-event.cc
1 /* Subclasses of diagnostic_event for analyzer diagnostics.
2    Copyright (C) 2019-2022 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 "config.h"
22 #define INCLUDE_MEMORY
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tree.h"
26 #include "function.h"
27 #include "basic-block.h"
28 #include "gimple.h"
29 #include "diagnostic-core.h"
30 #include "gimple-pretty-print.h"
31 #include "fold-const.h"
32 #include "diagnostic-path.h"
33 #include "options.h"
34 #include "cgraph.h"
35 #include "cfg.h"
36 #include "digraph.h"
37 #include "diagnostic-event-id.h"
38 #include "analyzer/analyzer.h"
39 #include "analyzer/analyzer-logging.h"
40 #include "analyzer/sm.h"
41 #include "sbitmap.h"
42 #include "bitmap.h"
43 #include "ordered-hash-map.h"
44 #include "analyzer/call-string.h"
45 #include "analyzer/program-point.h"
46 #include "analyzer/store.h"
47 #include "analyzer/region-model.h"
48 #include "analyzer/program-state.h"
49 #include "analyzer/checker-path.h"
50 #include "gimple-iterator.h"
51 #include "inlining-iterator.h"
52 #include "analyzer/supergraph.h"
53 #include "analyzer/pending-diagnostic.h"
54 #include "analyzer/diagnostic-manager.h"
55 #include "analyzer/constraint-manager.h"
56 #include "analyzer/checker-event.h"
57 #include "analyzer/exploded-graph.h"
58
59 #if ENABLE_ANALYZER
60
61 namespace ana {
62
63 /* Get a string for EK.  */
64
65 const char *
66 event_kind_to_string (enum event_kind ek)
67 {
68   switch (ek)
69     {
70     default:
71       gcc_unreachable ();
72     case EK_DEBUG:
73       return "EK_DEBUG";
74     case EK_CUSTOM:
75       return "EK_CUSTOM";
76     case EK_STMT:
77       return "EK_STMT";
78     case EK_REGION_CREATION:
79       return "EK_REGION_CREATION";
80     case EK_FUNCTION_ENTRY:
81       return "EK_FUNCTION_ENTRY";
82     case EK_STATE_CHANGE:
83       return "EK_STATE_CHANGE";
84     case EK_START_CFG_EDGE:
85       return "EK_START_CFG_EDGE";
86     case EK_END_CFG_EDGE:
87       return "EK_END_CFG_EDGE";
88     case EK_CALL_EDGE:
89       return "EK_CALL_EDGE";
90     case EK_RETURN_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";
96     case EK_INLINED_CALL:
97       return "EK_INLINED_CALL";
98     case EK_SETJMP:
99       return "EK_SETJMP";
100     case EK_REWIND_FROM_LONGJMP:
101       return "EK_REWIND_FROM_LONGJMP";
102     case EK_REWIND_TO_SETJMP:
103       return "EK_REWIND_TO_SETJMP";
104     case EK_WARNING:
105       return "EK_WARNING";
106     }
107 }
108
109 /* A class for fixing up fndecls and stack depths in checker_event, based
110    on inlining records.
111
112    The early inliner runs before the analyzer, which can lead to confusing
113    output.
114
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.  */
119
120 class inlining_info
121 {
122 public:
123   inlining_info (location_t loc)
124   {
125     inlining_iterator iter (loc);
126     m_inner_fndecl = iter.get_fndecl ();
127     int num_frames = 0;
128     while (!iter.done_p ())
129       {
130         m_outer_fndecl = iter.get_fndecl ();
131         num_frames++;
132         iter.next ();
133       }
134     if (num_frames > 1)
135       m_extra_frames = num_frames - 1;
136     else
137       m_extra_frames = 0;
138   }
139
140   tree get_inner_fndecl () const { return m_inner_fndecl; }
141   int get_extra_frames () const { return m_extra_frames; }
142
143 private:
144   tree m_outer_fndecl;
145   tree m_inner_fndecl;
146   int m_extra_frames;
147 };
148
149 /* class checker_event : public diagnostic_event.  */
150
151 /* checker_event's ctor.  */
152
153 checker_event::checker_event (enum event_kind kind,
154                               location_t loc, tree fndecl, int depth)
155 : m_kind (kind), m_loc (loc),
156   m_original_fndecl (fndecl), m_effective_fndecl (fndecl),
157   m_original_depth (depth), m_effective_depth (depth),
158   m_pending_diagnostic (NULL), m_emission_id (),
159   m_logical_loc (fndecl)
160 {
161   /* Update effective fndecl and depth if inlining has been recorded.  */
162   if (flag_analyzer_undo_inlining)
163     {
164       inlining_info info (loc);
165       if (info.get_inner_fndecl ())
166         {
167           m_effective_fndecl = info.get_inner_fndecl ();
168           m_effective_depth += info.get_extra_frames ();
169           m_logical_loc = tree_logical_location (m_effective_fndecl);
170         }
171     }
172 }
173
174 /* No-op implementation of diagnostic_event::get_meaning vfunc for
175    checker_event: checker events have no meaning by default.  */
176
177 diagnostic_event::meaning
178 checker_event::get_meaning () const
179 {
180   return meaning ();
181 }
182
183 /* Dump this event to PP (for debugging/logging purposes).  */
184
185 void
186 checker_event::dump (pretty_printer *pp) const
187 {
188   label_text event_desc (get_desc (false));
189   pp_printf (pp, "\"%s\" (depth %i",
190              event_desc.get (), m_effective_depth);
191
192   if (m_effective_depth != m_original_depth)
193     pp_printf (pp, " corrected from %i",
194                m_original_depth);
195   if (m_effective_fndecl)
196     {
197       pp_printf (pp, ", fndecl %qE", m_effective_fndecl);
198       if (m_effective_fndecl != m_original_fndecl)
199         pp_printf (pp, " corrected from %qE", m_original_fndecl);
200     }
201   pp_printf (pp, ", m_loc=%x)",
202              get_location ());
203 }
204
205 /* Dump this event to stderr (for debugging/logging purposes).  */
206
207 DEBUG_FUNCTION void
208 checker_event::debug () const
209 {
210   pretty_printer pp;
211   pp_format_decoder (&pp) = default_tree_printer;
212   pp_show_color (&pp) = pp_show_color (global_dc->printer);
213   pp.buffer->stream = stderr;
214   dump (&pp);
215   pp_newline (&pp);
216   pp_flush (&pp);
217 }
218
219 /* Hook for being notified when this event has its final id EMISSION_ID
220    and is about to emitted for PD.
221
222    Base implementation of checker_event::prepare_for_emission vfunc;
223    subclasses that override this should chain up to it.
224
225    Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
226    side-effects of the call to get_desc take place before
227    pending_diagnostic::emit is called.
228
229    For example, state_change_event::get_desc can call
230    pending_diagnostic::describe_state_change; free_of_non_heap can use this
231    to tweak the message (TODO: would be neater to simply capture the
232    pertinent data within the sm-state).  */
233
234 void
235 checker_event::prepare_for_emission (checker_path *,
236                                      pending_diagnostic *pd,
237                                      diagnostic_event_id_t emission_id)
238 {
239   m_pending_diagnostic = pd;
240   m_emission_id = emission_id;
241
242   label_text desc = get_desc (false);
243 }
244
245 /* class debug_event : public checker_event.  */
246
247 /* Implementation of diagnostic_event::get_desc vfunc for
248    debug_event.
249    Use the saved string as the event's description.  */
250
251 label_text
252 debug_event::get_desc (bool) const
253 {
254   return label_text::borrow (m_desc);
255 }
256
257 /* class precanned_custom_event : public custom_event.  */
258
259 /* Implementation of diagnostic_event::get_desc vfunc for
260    precanned_custom_event.
261    Use the saved string as the event's description.  */
262
263 label_text
264 precanned_custom_event::get_desc (bool) const
265 {
266   return label_text::borrow (m_desc);
267 }
268
269 /* class statement_event : public checker_event.  */
270
271 /* statement_event's ctor.  */
272
273 statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
274                                   const program_state &dst_state)
275 : checker_event (EK_STMT, gimple_location (stmt), fndecl, depth),
276   m_stmt (stmt),
277   m_dst_state (dst_state)
278 {
279 }
280
281 /* Implementation of diagnostic_event::get_desc vfunc for
282    statement_event.
283    Use the statement's dump form as the event's description.  */
284
285 label_text
286 statement_event::get_desc (bool) const
287 {
288   pretty_printer pp;
289   pp_string (&pp, "stmt: ");
290   pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
291   return label_text::take (xstrdup (pp_formatted_text (&pp)));
292 }
293
294 /* class region_creation_event : public checker_event.  */
295
296 region_creation_event::region_creation_event (location_t loc,
297                                               tree fndecl,
298                                               int depth)
299 : checker_event (EK_REGION_CREATION, loc, fndecl, depth)
300 {
301 }
302
303 /* The various region_creation_event subclasses' get_desc
304    implementations.  */
305
306 label_text
307 region_creation_event_memory_space::get_desc (bool) const
308 {
309   switch (m_mem_space)
310     {
311     default:
312       return label_text::borrow ("region created here");
313     case MEMSPACE_STACK:
314       return label_text::borrow ("region created on stack here");
315     case MEMSPACE_HEAP:
316       return label_text::borrow ("region created on heap here");
317     }
318 }
319
320 label_text
321 region_creation_event_capacity::get_desc (bool can_colorize) const
322 {
323   gcc_assert (m_capacity);
324   if (TREE_CODE (m_capacity) == INTEGER_CST)
325     {
326       unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
327       return make_label_text_n (can_colorize,
328                                 hwi,
329                                 "capacity: %wu byte",
330                                 "capacity: %wu bytes",
331                                 hwi);
332     }
333   else
334     return make_label_text (can_colorize,
335                             "capacity: %qE bytes", m_capacity);
336 }
337
338 label_text
339 region_creation_event_allocation_size::get_desc (bool can_colorize) const
340 {
341   if (m_capacity)
342     {
343       if (TREE_CODE (m_capacity) == INTEGER_CST)
344         return make_label_text_n (can_colorize,
345                                   tree_to_uhwi (m_capacity),
346                                   "allocated %E byte here",
347                                   "allocated %E bytes here",
348                                   m_capacity);
349       else
350         return make_label_text (can_colorize,
351                                 "allocated %qE bytes here",
352                                 m_capacity);
353     }
354   return make_label_text (can_colorize, "allocated here");
355 }
356
357 label_text
358 region_creation_event_debug::get_desc (bool) const
359 {
360   pretty_printer pp;
361   pp_format_decoder (&pp) = default_tree_printer;
362   pp_string (&pp, "region creation: ");
363   m_reg->dump_to_pp (&pp, true);
364   if (m_capacity)
365     pp_printf (&pp, " capacity: %qE", m_capacity);
366   return label_text::take (xstrdup (pp_formatted_text (&pp)));
367 }
368
369 /* class function_entry_event : public checker_event.  */
370
371 function_entry_event::function_entry_event (const program_point &dst_point)
372 : checker_event (EK_FUNCTION_ENTRY,
373                  dst_point.get_supernode ()->get_start_location (),
374                  dst_point.get_fndecl (),
375                  dst_point.get_stack_depth ())
376 {
377 }
378
379 /* Implementation of diagnostic_event::get_desc vfunc for
380    function_entry_event.
381
382    Use a string such as "entry to 'foo'" as the event's description.  */
383
384 label_text
385 function_entry_event::get_desc (bool can_colorize) const
386 {
387   return make_label_text (can_colorize, "entry to %qE", m_effective_fndecl);
388 }
389
390 /* Implementation of diagnostic_event::get_meaning vfunc for
391    function entry.  */
392
393 diagnostic_event::meaning
394 function_entry_event::get_meaning () const
395 {
396   return meaning (VERB_enter, NOUN_function);
397 }
398
399 /* class state_change_event : public checker_event.  */
400
401 /* state_change_event's ctor.  */
402
403 state_change_event::state_change_event (const supernode *node,
404                                         const gimple *stmt,
405                                         int stack_depth,
406                                         const state_machine &sm,
407                                         const svalue *sval,
408                                         state_machine::state_t from,
409                                         state_machine::state_t to,
410                                         const svalue *origin,
411                                         const program_state &dst_state)
412 : checker_event (EK_STATE_CHANGE,
413                  stmt->location, node->m_fun->decl,
414                  stack_depth),
415   m_node (node), m_stmt (stmt), m_sm (sm),
416   m_sval (sval), m_from (from), m_to (to),
417   m_origin (origin),
418   m_dst_state (dst_state)
419 {
420 }
421
422 /* Implementation of diagnostic_event::get_desc vfunc for
423    state_change_event.
424
425    Attempt to generate a nicer human-readable description.
426    For greatest precision-of-wording, give the pending diagnostic
427    a chance to describe this state change (in terms of the
428    diagnostic).
429    Note that we only have a pending_diagnostic set on the event once
430    the diagnostic is about to being emitted, so the description for
431    an event can change.  */
432
433 label_text
434 state_change_event::get_desc (bool can_colorize) const
435 {
436   if (m_pending_diagnostic)
437     {
438       region_model *model = m_dst_state.m_region_model;
439       tree var = model->get_representative_tree (m_sval);
440       tree origin = model->get_representative_tree (m_origin);
441       label_text custom_desc
442         = m_pending_diagnostic->describe_state_change
443             (evdesc::state_change (can_colorize, var, origin,
444                                    m_from, m_to, m_emission_id, *this));
445       if (custom_desc.get ())
446         {
447           if (flag_analyzer_verbose_state_changes)
448             {
449               /* Get any "meaning" of event.  */
450               diagnostic_event::meaning meaning = get_meaning ();
451               pretty_printer meaning_pp;
452               meaning.dump_to_pp (&meaning_pp);
453
454               /* Append debug version.  */
455               if (m_origin)
456                 return make_label_text
457                   (can_colorize,
458                    "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
459                    custom_desc.get (),
460                    var,
461                    m_from->get_name (),
462                    m_to->get_name (),
463                    origin,
464                    pp_formatted_text (&meaning_pp));
465               else
466                 return make_label_text
467                   (can_colorize,
468                    "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
469                    custom_desc.get (),
470                    var,
471                    m_from->get_name (),
472                    m_to->get_name (),
473                    pp_formatted_text (&meaning_pp));
474             }
475           else
476             return custom_desc;
477         }
478     }
479
480   /* Fallback description.  */
481   if (m_sval)
482     {
483       label_text sval_desc = m_sval->get_desc ();
484       if (m_origin)
485         {
486           label_text origin_desc = m_origin->get_desc ();
487           return make_label_text
488             (can_colorize,
489              "state of %qs: %qs -> %qs (origin: %qs)",
490              sval_desc.get (),
491              m_from->get_name (),
492              m_to->get_name (),
493              origin_desc.get ());
494         }
495       else
496         return make_label_text
497           (can_colorize,
498            "state of %qs: %qs -> %qs (NULL origin)",
499            sval_desc.get (),
500            m_from->get_name (),
501            m_to->get_name ());
502     }
503   else
504     {
505       gcc_assert (m_origin == NULL);
506       return make_label_text
507         (can_colorize,
508          "global state: %qs -> %qs",
509          m_from->get_name (),
510          m_to->get_name ());
511     }
512 }
513
514 /* Implementation of diagnostic_event::get_meaning vfunc for
515    state change events: delegate to the pending_diagnostic to
516    get any meaning.  */
517
518 diagnostic_event::meaning
519 state_change_event::get_meaning () const
520 {
521   if (m_pending_diagnostic)
522     {
523       region_model *model = m_dst_state.m_region_model;
524       tree var = model->get_representative_tree (m_sval);
525       tree origin = model->get_representative_tree (m_origin);
526       return m_pending_diagnostic->get_meaning_for_state_change
527         (evdesc::state_change (false, var, origin,
528                                m_from, m_to, m_emission_id, *this));
529     }
530   else
531     return meaning ();
532 }
533
534 /* class superedge_event : public checker_event.  */
535
536 /* Get the callgraph_superedge for this superedge_event, which must be
537    for an interprocedural edge, rather than a CFG edge.  */
538
539 const callgraph_superedge&
540 superedge_event::get_callgraph_superedge () const
541 {
542   gcc_assert (m_sedge->m_kind != SUPEREDGE_CFG_EDGE);
543   return *m_sedge->dyn_cast_callgraph_superedge ();
544 }
545
546 /* Determine if this event should be filtered at the given verbosity
547    level.  */
548
549 bool
550 superedge_event::should_filter_p (int verbosity) const
551 {
552   switch (m_sedge->m_kind)
553     {
554     case SUPEREDGE_CFG_EDGE:
555       {
556         if (verbosity < 2)
557           return true;
558
559         if (verbosity < 4)
560           {
561             /* Filter events with empty descriptions.  This ought to filter
562                FALLTHRU, but retain true/false/switch edges.  */
563             label_text desc = get_desc (false);
564             gcc_assert (desc.get ());
565             if (desc.get ()[0] == '\0')
566               return true;
567           }
568       }
569       break;
570
571     default:
572       break;
573     }
574   return false;
575 }
576
577 /* superedge_event's ctor.  */
578
579 superedge_event::superedge_event (enum event_kind kind,
580                                   const exploded_edge &eedge,
581                                   location_t loc, tree fndecl, int depth)
582 : checker_event (kind, loc, fndecl, depth),
583   m_eedge (eedge), m_sedge (eedge.m_sedge),
584   m_var (NULL_TREE), m_critical_state (0)
585 {
586 }
587
588 /* class cfg_edge_event : public superedge_event.  */
589
590 /* Get the cfg_superedge for this cfg_edge_event.  */
591
592 const cfg_superedge &
593 cfg_edge_event::get_cfg_superedge () const
594 {
595   return *m_sedge->dyn_cast_cfg_superedge ();
596 }
597
598 /* cfg_edge_event's ctor.  */
599
600 cfg_edge_event::cfg_edge_event (enum event_kind kind,
601                                 const exploded_edge &eedge,
602                                 location_t loc, tree fndecl, int depth)
603 : superedge_event (kind, eedge, loc, fndecl, depth)
604 {
605   gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
606 }
607
608 /* Implementation of diagnostic_event::get_meaning vfunc for
609    CFG edge events.  */
610
611 diagnostic_event::meaning
612 cfg_edge_event::get_meaning () const
613 {
614   const cfg_superedge& cfg_sedge = get_cfg_superedge ();
615   if (cfg_sedge.true_value_p ())
616     return meaning (VERB_branch, PROPERTY_true);
617   else if (cfg_sedge.false_value_p ())
618     return meaning (VERB_branch, PROPERTY_false);
619   else
620     return meaning ();
621 }
622
623 /* class start_cfg_edge_event : public cfg_edge_event.  */
624
625 /* Implementation of diagnostic_event::get_desc vfunc for
626    start_cfg_edge_event.
627
628    If -fanalyzer-verbose-edges, then generate low-level descriptions, such
629    as
630      "taking 'true' edge SN:7 -> SN:8".
631
632    Otherwise, generate strings using the label of the underlying CFG if
633    any, such as:
634      "following 'true' branch..." or
635      "following 'case 3' branch..."
636      "following 'default' branch..."
637
638    For conditionals, attempt to supply a description of the condition that
639    holds, such as:
640      "following 'false' branch (when 'ptr' is non-NULL)..."
641
642    Failing that, return an empty description (which will lead to this event
643    being filtered).  */
644
645 label_text
646 start_cfg_edge_event::get_desc (bool can_colorize) const
647 {
648   bool user_facing = !flag_analyzer_verbose_edges;
649   label_text edge_desc (m_sedge->get_description (user_facing));
650   if (user_facing)
651     {
652       if (edge_desc.get () && strlen (edge_desc.get ()) > 0)
653         {
654           label_text cond_desc = maybe_describe_condition (can_colorize);
655           label_text result;
656           if (cond_desc.get ())
657             return make_label_text (can_colorize,
658                                     "following %qs branch (%s)...",
659                                     edge_desc.get (), cond_desc.get ());
660           else
661             return make_label_text (can_colorize,
662                                     "following %qs branch...",
663                                     edge_desc.get ());
664         }
665       else
666         return label_text::borrow ("");
667     }
668   else
669     {
670       if (strlen (edge_desc.get ()) > 0)
671         return make_label_text (can_colorize,
672                                 "taking %qs edge SN:%i -> SN:%i",
673                                 edge_desc.get (),
674                                 m_sedge->m_src->m_index,
675                                 m_sedge->m_dest->m_index);
676       else
677         return make_label_text (can_colorize,
678                                 "taking edge SN:%i -> SN:%i",
679                                 m_sedge->m_src->m_index,
680                                 m_sedge->m_dest->m_index);
681     }
682 }
683
684 /* Attempt to generate a description of any condition that holds at this edge.
685
686    The intent is to make the user-facing messages more clear, especially for
687    cases where there's a single or double-negative, such as
688    when describing the false branch of an inverted condition.
689
690    For example, rather than printing just:
691
692       |  if (!ptr)
693       |     ~
694       |     |
695       |     (1) following 'false' branch...
696
697    it's clearer to spell out the condition that holds:
698
699       |  if (!ptr)
700       |     ~
701       |     |
702       |     (1) following 'false' branch (when 'ptr' is non-NULL)...
703                                           ^^^^^^^^^^^^^^^^^^^^^^
704
705    In the above example, this function would generate the highlighted
706    string: "when 'ptr' is non-NULL".
707
708    If the edge is not a condition, or it's not clear that a description of
709    the condition would be helpful to the user, return NULL.  */
710
711 label_text
712 start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const
713 {
714   const cfg_superedge& cfg_sedge = get_cfg_superedge ();
715
716   if (cfg_sedge.true_value_p () || cfg_sedge.false_value_p ())
717     {
718       const gimple *last_stmt = m_sedge->m_src->get_last_stmt ();
719       if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
720         {
721           enum tree_code op = gimple_cond_code (cond_stmt);
722           tree lhs = gimple_cond_lhs (cond_stmt);
723           tree rhs = gimple_cond_rhs (cond_stmt);
724           if (cfg_sedge.false_value_p ())
725             op = invert_tree_comparison (op, false /* honor_nans */);
726           return maybe_describe_condition (can_colorize,
727                                            lhs, op, rhs);
728         }
729     }
730   return label_text::borrow (NULL);
731 }
732
733 /* Subroutine of maybe_describe_condition above.
734
735    Attempt to generate a user-facing description of the condition
736    LHS OP RHS, but only if it is likely to make it easier for the
737    user to understand a condition.  */
738
739 label_text
740 start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
741                                                 tree lhs,
742                                                 enum tree_code op,
743                                                 tree rhs)
744 {
745   /* In theory we could just build a tree via
746        fold_build2 (op, boolean_type_node, lhs, rhs)
747      and print it with %qE on it, but this leads to warts such as
748      parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'.  */
749
750   /* Special-case: describe testing the result of strcmp, as figuring
751      out what the "true" or "false" path is can be confusing to the user.  */
752   if (TREE_CODE (lhs) == SSA_NAME
753       && zerop (rhs))
754     {
755       if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
756         if (is_special_named_call_p (call, "strcmp", 2))
757           {
758             if (op == EQ_EXPR)
759               return label_text::borrow ("when the strings are equal");
760             if (op == NE_EXPR)
761               return label_text::borrow ("when the strings are non-equal");
762           }
763     }
764
765   /* Only attempt to generate text for sufficiently simple expressions.  */
766   if (!should_print_expr_p (lhs))
767     return label_text::borrow (NULL);
768   if (!should_print_expr_p (rhs))
769     return label_text::borrow (NULL);
770
771   /* Special cases for pointer comparisons against NULL.  */
772   if (POINTER_TYPE_P (TREE_TYPE (lhs))
773       && POINTER_TYPE_P (TREE_TYPE (rhs))
774       && zerop (rhs))
775     {
776       if (op == EQ_EXPR)
777         return make_label_text (can_colorize, "when %qE is NULL",
778                                 lhs);
779       if (op == NE_EXPR)
780         return make_label_text (can_colorize, "when %qE is non-NULL",
781                                 lhs);
782     }
783
784   return make_label_text (can_colorize, "when %<%E %s %E%>",
785                           lhs, op_symbol_code (op), rhs);
786 }
787
788 /* Subroutine of maybe_describe_condition.
789
790    Return true if EXPR is we will get suitable user-facing output
791    from %E on it.  */
792
793 bool
794 start_cfg_edge_event::should_print_expr_p (tree expr)
795 {
796   if (TREE_CODE (expr) == SSA_NAME)
797     {
798       if (SSA_NAME_VAR (expr))
799         return should_print_expr_p (SSA_NAME_VAR (expr));
800       else
801         return false;
802     }
803
804   if (DECL_P (expr))
805     return true;
806
807   if (CONSTANT_CLASS_P (expr))
808     return true;
809
810   return false;
811 }
812
813 /* class call_event : public superedge_event.  */
814
815 /* call_event's ctor.  */
816
817 call_event::call_event (const exploded_edge &eedge,
818                         location_t loc, tree fndecl, int depth)
819 : superedge_event (EK_CALL_EDGE, eedge, loc, fndecl, depth)
820 {
821   if (eedge.m_sedge)
822     gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
823
824    m_src_snode = eedge.m_src->get_supernode ();
825    m_dest_snode = eedge.m_dest->get_supernode ();
826 }
827
828 /* Implementation of diagnostic_event::get_desc vfunc for
829    call_event.
830
831    If this call event passes critical state for an sm-based warning,
832    allow the diagnostic to generate a precise description, such as:
833
834      "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
835
836    Otherwise, generate a description of the form
837    "calling 'foo' from 'bar'".  */
838
839 label_text
840 call_event::get_desc (bool can_colorize) const
841 {
842   if (m_critical_state && m_pending_diagnostic)
843     {
844       gcc_assert (m_var);
845       tree var = fixup_tree_for_diagnostic (m_var);
846       label_text custom_desc
847         = m_pending_diagnostic->describe_call_with_state
848             (evdesc::call_with_state (can_colorize,
849                                       m_src_snode->m_fun->decl,
850                                       m_dest_snode->m_fun->decl,
851                                       var,
852                                       m_critical_state));
853       if (custom_desc.get ())
854         return custom_desc;
855     }
856
857   return make_label_text (can_colorize,
858                           "calling %qE from %qE",
859                           get_callee_fndecl (),
860                           get_caller_fndecl ());
861 }
862
863 /* Implementation of diagnostic_event::get_meaning vfunc for
864    function call events.  */
865
866 diagnostic_event::meaning
867 call_event::get_meaning () const
868 {
869   return meaning (VERB_call, NOUN_function);
870 }
871
872 /* Override of checker_event::is_call_p for calls.  */
873
874 bool
875 call_event::is_call_p () const
876 {
877   return true;
878 }
879
880 tree
881 call_event::get_caller_fndecl () const
882 {
883   return m_src_snode->m_fun->decl;
884 }
885
886 tree
887 call_event::get_callee_fndecl () const
888 {
889   return m_dest_snode->m_fun->decl;
890 }
891
892 /* class return_event : public superedge_event.  */
893
894 /* return_event's ctor.  */
895
896 return_event::return_event (const exploded_edge &eedge,
897                             location_t loc, tree fndecl, int depth)
898 : superedge_event (EK_RETURN_EDGE, eedge, loc, fndecl, depth)
899 {
900   if (eedge.m_sedge)
901     gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
902
903   m_src_snode = eedge.m_src->get_supernode ();
904   m_dest_snode = eedge.m_dest->get_supernode ();
905 }
906
907 /* Implementation of diagnostic_event::get_desc vfunc for
908    return_event.
909
910    If this return event returns critical state for an sm-based warning,
911    allow the diagnostic to generate a precise description, such as:
912
913       "possible of NULL to 'foo' from 'bar'"
914
915    Otherwise, generate a description of the form
916    "returning to 'foo' from 'bar'.  */
917
918 label_text
919 return_event::get_desc (bool can_colorize) const
920 {
921   /*  For greatest precision-of-wording, if this is returning the
922       state involved in the pending diagnostic, give the pending
923       diagnostic a chance to describe this return (in terms of
924       itself).  */
925   if (m_critical_state && m_pending_diagnostic)
926     {
927       label_text custom_desc
928         = m_pending_diagnostic->describe_return_of_state
929             (evdesc::return_of_state (can_colorize,
930                                       m_dest_snode->m_fun->decl,
931                                       m_src_snode->m_fun->decl,
932                                       m_critical_state));
933       if (custom_desc.get ())
934         return custom_desc;
935     }
936   return make_label_text (can_colorize,
937                           "returning to %qE from %qE",
938                           m_dest_snode->m_fun->decl,
939                           m_src_snode->m_fun->decl);
940 }
941
942 /* Implementation of diagnostic_event::get_meaning vfunc for
943    function return events.  */
944
945 diagnostic_event::meaning
946 return_event::get_meaning () const
947 {
948   return meaning (VERB_return, NOUN_function);
949 }
950
951 /* Override of checker_event::is_return_p for returns.  */
952
953 bool
954 return_event::is_return_p () const
955 {
956   return true;
957 }
958
959 /* class start_consolidated_cfg_edges_event : public checker_event.  */
960
961 label_text
962 start_consolidated_cfg_edges_event::get_desc (bool can_colorize) const
963 {
964   return make_label_text (can_colorize,
965                           "following %qs branch...",
966                           m_edge_sense ? "true" : "false");
967 }
968
969 /* Implementation of diagnostic_event::get_meaning vfunc for
970    start_consolidated_cfg_edges_event.  */
971
972 diagnostic_event::meaning
973 start_consolidated_cfg_edges_event::get_meaning () const
974 {
975   return meaning (VERB_branch,
976                   (m_edge_sense ? PROPERTY_true : PROPERTY_false));
977 }
978
979 /* class inlined_call_event : public checker_event.  */
980
981 label_text
982 inlined_call_event::get_desc (bool can_colorize) const
983 {
984   return make_label_text (can_colorize,
985                           "inlined call to %qE from %qE",
986                           m_apparent_callee_fndecl,
987                           m_apparent_caller_fndecl);
988 }
989
990 /* Implementation of diagnostic_event::get_meaning vfunc for
991    reconstructed inlined function calls.  */
992
993 diagnostic_event::meaning
994 inlined_call_event::get_meaning () const
995 {
996   return meaning (VERB_call, NOUN_function);
997 }
998
999 /* class setjmp_event : public checker_event.  */
1000
1001 /* Implementation of diagnostic_event::get_desc vfunc for
1002    setjmp_event.  */
1003
1004 label_text
1005 setjmp_event::get_desc (bool can_colorize) const
1006 {
1007   return make_label_text (can_colorize,
1008                           "%qs called here",
1009                           get_user_facing_name (m_setjmp_call));
1010 }
1011
1012 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1013
1014    Record this setjmp's event ID into the path, so that rewind events can
1015    use it.  */
1016
1017 void
1018 setjmp_event::prepare_for_emission (checker_path *path,
1019                                     pending_diagnostic *pd,
1020                                     diagnostic_event_id_t emission_id)
1021 {
1022   checker_event::prepare_for_emission (path, pd, emission_id);
1023   path->record_setjmp_event (m_enode, emission_id);
1024 }
1025
1026 /* class rewind_event : public checker_event.  */
1027
1028 /* Get the fndecl containing the site of the longjmp call.  */
1029
1030 tree
1031 rewind_event::get_longjmp_caller () const
1032 {
1033   return m_eedge->m_src->get_function ()->decl;
1034 }
1035
1036 /* Get the fndecl containing the site of the setjmp call.  */
1037
1038 tree
1039 rewind_event::get_setjmp_caller () const
1040 {
1041   return m_eedge->m_dest->get_function ()->decl;
1042 }
1043
1044 /* rewind_event's ctor.  */
1045
1046 rewind_event::rewind_event (const exploded_edge *eedge,
1047                             enum event_kind kind,
1048                             location_t loc, tree fndecl, int depth,
1049                             const rewind_info_t *rewind_info)
1050 : checker_event (kind, loc, fndecl, depth),
1051   m_rewind_info (rewind_info),
1052   m_eedge (eedge)
1053 {
1054   gcc_assert (m_eedge->m_custom_info.get () == m_rewind_info);
1055 }
1056
1057 /* class rewind_from_longjmp_event : public rewind_event.  */
1058
1059 /* Implementation of diagnostic_event::get_desc vfunc for
1060    rewind_from_longjmp_event.  */
1061
1062 label_text
1063 rewind_from_longjmp_event::get_desc (bool can_colorize) const
1064 {
1065   const char *src_name
1066     = get_user_facing_name (m_rewind_info->get_longjmp_call ());
1067
1068   if (get_longjmp_caller () == get_setjmp_caller ())
1069     /* Special-case: purely intraprocedural rewind.  */
1070     return make_label_text (can_colorize,
1071                             "rewinding within %qE from %qs...",
1072                             get_longjmp_caller (),
1073                             src_name);
1074   else
1075     return make_label_text (can_colorize,
1076                             "rewinding from %qs in %qE...",
1077                             src_name,
1078                             get_longjmp_caller ());
1079 }
1080
1081 /* class rewind_to_setjmp_event : public rewind_event.  */
1082
1083 /* Implementation of diagnostic_event::get_desc vfunc for
1084    rewind_to_setjmp_event.  */
1085
1086 label_text
1087 rewind_to_setjmp_event::get_desc (bool can_colorize) const
1088 {
1089   const char *dst_name
1090     = get_user_facing_name (m_rewind_info->get_setjmp_call ());
1091
1092   /* If we can, identify the ID of the setjmp_event.  */
1093   if (m_original_setjmp_event_id.known_p ())
1094     {
1095       if (get_longjmp_caller () == get_setjmp_caller ())
1096         /* Special-case: purely intraprocedural rewind.  */
1097         return make_label_text (can_colorize,
1098                                 "...to %qs (saved at %@)",
1099                                 dst_name,
1100                                 &m_original_setjmp_event_id);
1101       else
1102         return make_label_text (can_colorize,
1103                                 "...to %qs in %qE (saved at %@)",
1104                                 dst_name,
1105                                 get_setjmp_caller (),
1106                                 &m_original_setjmp_event_id);
1107     }
1108   else
1109     {
1110       if (get_longjmp_caller () == get_setjmp_caller ())
1111         /* Special-case: purely intraprocedural rewind.  */
1112         return make_label_text (can_colorize,
1113                                 "...to %qs",
1114                                 dst_name,
1115                                 get_setjmp_caller ());
1116       else
1117         return make_label_text (can_colorize,
1118                                 "...to %qs in %qE",
1119                                 dst_name,
1120                                 get_setjmp_caller ());
1121     }
1122 }
1123
1124 /* Implementation of checker_event::prepare_for_emission vfunc for
1125    rewind_to_setjmp_event.
1126
1127    Attempt to look up the setjmp event ID that recorded the jmp_buf
1128    for this rewind.  */
1129
1130 void
1131 rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
1132                                               pending_diagnostic *pd,
1133                                               diagnostic_event_id_t emission_id)
1134 {
1135   checker_event::prepare_for_emission (path, pd, emission_id);
1136   path->get_setjmp_event (m_rewind_info->get_enode_origin (),
1137                           &m_original_setjmp_event_id);
1138 }
1139
1140 /* class warning_event : public checker_event.  */
1141
1142 /* Implementation of diagnostic_event::get_desc vfunc for
1143    warning_event.
1144
1145    If the pending diagnostic implements describe_final_event, use it,
1146    generating a precise description e.g.
1147      "second 'free' here; first 'free' was at (7)"
1148
1149    Otherwise generate a generic description.  */
1150
1151 label_text
1152 warning_event::get_desc (bool can_colorize) const
1153 {
1154   if (m_pending_diagnostic)
1155     {
1156       tree var = fixup_tree_for_diagnostic (m_var);
1157       label_text ev_desc
1158         = m_pending_diagnostic->describe_final_event
1159             (evdesc::final_event (can_colorize, var, m_state));
1160       if (ev_desc.get ())
1161         {
1162           if (m_sm && flag_analyzer_verbose_state_changes)
1163             {
1164               if (var)
1165                 return make_label_text (can_colorize,
1166                                         "%s (%qE is in state %qs)",
1167                                         ev_desc.get (),
1168                                         var, m_state->get_name ());
1169               else
1170                 return make_label_text (can_colorize,
1171                                         "%s (in global state %qs)",
1172                                         ev_desc.get (),
1173                                         m_state->get_name ());
1174             }
1175           else
1176             return ev_desc;
1177         }
1178     }
1179
1180   if (m_sm)
1181     {
1182       if (m_var)
1183         return make_label_text (can_colorize,
1184                                 "here (%qE is in state %qs)",
1185                                 m_var, m_state->get_name ());
1186       else
1187         return make_label_text (can_colorize,
1188                                 "here (in global state %qs)",
1189                                 m_state->get_name ());
1190     }
1191   else
1192     return label_text::borrow ("here");
1193 }
1194
1195 /* Implementation of diagnostic_event::get_meaning vfunc for
1196    warning_event.  */
1197
1198 diagnostic_event::meaning
1199 warning_event::get_meaning () const
1200 {
1201   return meaning (VERB_danger, NOUN_unknown);
1202 }
1203
1204 } // namespace ana
1205
1206 #endif /* #if ENABLE_ANALYZER */