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