analyzer: introduce struct event_loc_info
[platform/upstream/gcc.git] / gcc / analyzer / checker-path.h
index 7b86d48..de1f620 100644 (file)
@@ -1,5 +1,5 @@
-/* Subclasses of diagnostic_path and diagnostic_event for analyzer diagnostics.
-   Copyright (C) 2019-2020 Free Software Foundation, Inc.
+/* Subclass of diagnostic_path for analyzer diagnostics.
+   Copyright (C) 2019-2022 Free Software Foundation, Inc.
    Contributed by David Malcolm <dmalcolm@redhat.com>.
 
 This file is part of GCC.
@@ -21,441 +21,25 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_ANALYZER_CHECKER_PATH_H
 #define GCC_ANALYZER_CHECKER_PATH_H
 
-namespace ana {
-
-/* An enum for discriminating between the concrete subclasses of
-   checker_event.  */
-
-enum event_kind
-{
-  EK_DEBUG,
-  EK_CUSTOM,
-  EK_STMT,
-  EK_FUNCTION_ENTRY,
-  EK_STATE_CHANGE,
-  EK_START_CFG_EDGE,
-  EK_END_CFG_EDGE,
-  EK_CALL_EDGE,
-  EK_RETURN_EDGE,
-  EK_SETJMP,
-  EK_REWIND_FROM_LONGJMP,
-  EK_REWIND_TO_SETJMP,
-  EK_WARNING
-};
-
-extern const char *event_kind_to_string (enum event_kind ek);
-
-/* Event subclasses.
-
-   The class hierarchy looks like this (using indentation to show
-   inheritance, and with event_kinds shown for the concrete subclasses):
-
-   diagnostic_event
-     checker_event
-       debug_event (EK_DEBUG)
-       custom_event (EK_CUSTOM)
-       statement_event (EK_STMT)
-       function_entry_event (EK_FUNCTION_ENTRY)
-       state_change_event (EK_STATE_CHANGE)
-       superedge_event
-         cfg_edge_event
-          start_cfg_edge_event (EK_START_CFG_EDGE)
-          end_cfg_edge_event (EK_END_CFG_EDGE)
-         call_event (EK_CALL_EDGE)
-         return_edge (EK_RETURN_EDGE)
-       setjmp_event (EK_SETJMP)
-       rewind_event
-         rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
-        rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
-       warning_event (EK_WARNING).  */
-
-/* Abstract subclass of diagnostic_event; the base class for use in
-   checker_path (the analyzer's diagnostic_path subclass).  */
-
-class checker_event : public diagnostic_event
-{
-public:
-  checker_event (enum event_kind kind,
-                location_t loc, tree fndecl, int depth)
-    : m_kind (kind), m_loc (loc), m_fndecl (fndecl), m_depth (depth),
-      m_pending_diagnostic (NULL), m_emission_id ()
-  {
-  }
-
-  /* Implementation of diagnostic_event.  */
-
-  location_t get_location () const FINAL OVERRIDE { return m_loc; }
-  tree get_fndecl () const FINAL OVERRIDE { return m_fndecl; }
-  int get_stack_depth () const FINAL OVERRIDE { return m_depth; }
-
-  /* Additional functionality.  */
-
-  virtual void prepare_for_emission (checker_path *,
-                                    pending_diagnostic *pd,
-                                    diagnostic_event_id_t emission_id);
-  virtual bool is_call_p () const { return false; }
-  virtual bool is_function_entry_p () const  { return false; }
-  virtual bool is_return_p () const  { return false; }
-
-  void dump (pretty_printer *pp) const;
-
- public:
-  const enum event_kind m_kind;
- protected:
-  location_t m_loc;
-  tree m_fndecl;
-  int m_depth;
-  pending_diagnostic *m_pending_diagnostic;
-  diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
-};
-
-/* A concrete event subclass for a purely textual event, for use in
-   debugging path creation and filtering.  */
-
-class debug_event : public checker_event
-{
-public:
-  debug_event (location_t loc, tree fndecl, int depth,
-             const char *desc)
-  : checker_event (EK_DEBUG, loc, fndecl, depth),
-    m_desc (xstrdup (desc))
-  {
-  }
-  ~debug_event ()
-  {
-    free (m_desc);
-  }
-
-  label_text get_desc (bool) const FINAL OVERRIDE;
-
-private:
-  char *m_desc;
-};
-
-/* A concrete event subclass for custom events.  These are not filtered,
-   as they are likely to be pertinent to the diagnostic.  */
-
-class custom_event : public checker_event
-{
-public:
-  custom_event (location_t loc, tree fndecl, int depth,
-               const char *desc)
-  : checker_event (EK_CUSTOM, loc, fndecl, depth),
-    m_desc (xstrdup (desc))
-  {
-  }
-  ~custom_event ()
-  {
-    free (m_desc);
-  }
-
-  label_text get_desc (bool) const FINAL OVERRIDE;
-
-private:
-  char *m_desc;
-};
-
-/* A concrete event subclass describing the execution of a gimple statement,
-   for use at high verbosity levels when debugging paths.  */
-
-class statement_event : public checker_event
-{
-public:
-  statement_event (const gimple *stmt, tree fndecl, int depth,
-                  const program_state &dst_state);
-
-  label_text get_desc (bool) const FINAL OVERRIDE;
-
-  const gimple * const m_stmt;
-  const program_state m_dst_state;
-};
-
-/* An event subclass describing the entry to a function.  */
-
-class function_entry_event : public checker_event
-{
-public:
-  function_entry_event (location_t loc, tree fndecl, int depth)
-  : checker_event (EK_FUNCTION_ENTRY, loc, fndecl, depth)
-  {
-  }
-
-  label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
-
-  bool is_function_entry_p () const FINAL OVERRIDE { return true; }
-};
-
-/* Subclass of checker_event describing a state change.  */
-
-class state_change_event : public checker_event
-{
-public:
-  state_change_event (const supernode *node, const gimple *stmt,
-                     int stack_depth,
-                     const state_machine &sm,
-                     const svalue *sval,
-                     state_machine::state_t from,
-                     state_machine::state_t to,
-                     const svalue *origin,
-                     const program_state &dst_state);
-
-  label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
-
-  function *get_dest_function () const
-  {
-    return m_dst_state.get_current_function ();
-  }
-
-  const supernode *m_node;
-  const gimple *m_stmt;
-  const state_machine &m_sm;
-  const svalue *m_sval;
-  state_machine::state_t m_from;
-  state_machine::state_t m_to;
-  const svalue *m_origin;
-  program_state m_dst_state;
-};
+#include "analyzer/checker-event.h"
 
-/* Subclass of checker_event; parent class for subclasses that relate to
-   a superedge.  */
-
-class superedge_event : public checker_event
-{
-public:
-  /* Mark this edge event as being either an interprocedural call or
-     return in which VAR is in STATE, and that this is critical to the
-     diagnostic (so that get_desc can attempt to get a better description
-     from any pending_diagnostic).  */
-  void record_critical_state (tree var, state_machine::state_t state)
-  {
-    m_var = var;
-    m_critical_state = state;
-  }
-
-  const callgraph_superedge& get_callgraph_superedge () const;
-
-  bool should_filter_p (int verbosity) const;
-
- protected:
-  superedge_event (enum event_kind kind, const exploded_edge &eedge,
-                  location_t loc, tree fndecl, int depth);
-
- public:
-  const exploded_edge &m_eedge;
-  const superedge *m_sedge;
-  tree m_var;
-  state_machine::state_t m_critical_state;
-};
-
-/* An abstract event subclass for when a CFG edge is followed; it has two
-   subclasses, representing the start of the edge and the end of the
-   edge, which come in pairs.  */
-
-class cfg_edge_event : public superedge_event
-{
-public:
-  const cfg_superedge& get_cfg_superedge () const;
-
- protected:
-  cfg_edge_event (enum event_kind kind, const exploded_edge &eedge,
-                 location_t loc, tree fndecl, int depth);
-};
-
-/* A concrete event subclass for the start of a CFG edge
-   e.g. "following 'false' branch...'.  */
-
-class start_cfg_edge_event : public cfg_edge_event
-{
-public:
-  start_cfg_edge_event (const exploded_edge &eedge,
-                       location_t loc, tree fndecl, int depth)
-  : cfg_edge_event (EK_START_CFG_EDGE, eedge, loc, fndecl, depth)
-  {
-  }
-
-  label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
-
- private:
-  label_text maybe_describe_condition (bool can_colorize) const;
-
-  static label_text maybe_describe_condition (bool can_colorize,
-                                             tree lhs,
-                                             enum tree_code op,
-                                             tree rhs);
-  static bool should_print_expr_p (tree);
-};
-
-/* A concrete event subclass for the end of a CFG edge
-   e.g. "...to here'.  */
-
-class end_cfg_edge_event : public cfg_edge_event
-{
-public:
-  end_cfg_edge_event (const exploded_edge &eedge,
-                     location_t loc, tree fndecl, int depth)
-  : cfg_edge_event (EK_END_CFG_EDGE, eedge, loc, fndecl, depth)
-  {
-  }
-
-  label_text get_desc (bool /*can_colorize*/) const FINAL OVERRIDE
-  {
-    return label_text::borrow ("...to here");
-  }
-};
-
-/* A concrete event subclass for an interprocedural call.  */
-
-class call_event : public superedge_event
-{
-public:
-  call_event (const exploded_edge &eedge,
-             location_t loc, tree fndecl, int depth);
-
-  label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
-
-  bool is_call_p () const FINAL OVERRIDE;
-};
-
-/* A concrete event subclass for an interprocedural return.  */
-
-class return_event : public superedge_event
-{
-public:
-  return_event (const exploded_edge &eedge,
-               location_t loc, tree fndecl, int depth);
-
-  label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
-
-  bool is_return_p () const FINAL OVERRIDE;
-};
-
-/* A concrete event subclass for a setjmp or sigsetjmp call.  */
-
-class setjmp_event : public checker_event
-{
-public:
-  setjmp_event (location_t loc, const exploded_node *enode,
-               tree fndecl, int depth, const gcall *setjmp_call)
-  : checker_event (EK_SETJMP, loc, fndecl, depth),
-    m_enode (enode), m_setjmp_call (setjmp_call)
-  {
-  }
-
-  label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
-
-  void prepare_for_emission (checker_path *path,
-                            pending_diagnostic *pd,
-                            diagnostic_event_id_t emission_id) FINAL OVERRIDE;
-
-private:
-  const exploded_node *m_enode;
-  const gcall *m_setjmp_call;
-};
-
-/* An abstract event subclass for rewinding from a longjmp to a setjmp
-   (or siglongjmp to sigsetjmp).
-
-   Base class for two from/to subclasses, showing the two halves of the
-   rewind.  */
-
-class rewind_event : public checker_event
-{
-public:
-  tree get_longjmp_caller () const;
-  tree get_setjmp_caller () const;
-  const exploded_edge *get_eedge () const { return m_eedge; }
-
- protected:
-  rewind_event (const exploded_edge *eedge,
-               enum event_kind kind,
-               location_t loc, tree fndecl, int depth,
-               const rewind_info_t *rewind_info);
-  const rewind_info_t *m_rewind_info;
-
- private:
-  const exploded_edge *m_eedge;
-};
-
-/* A concrete event subclass for rewinding from a longjmp to a setjmp,
-   showing the longjmp (or siglongjmp).  */
-
-class rewind_from_longjmp_event : public rewind_event
-{
-public:
-  rewind_from_longjmp_event (const exploded_edge *eedge,
-                            location_t loc, tree fndecl, int depth,
-                            const rewind_info_t *rewind_info)
-  : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc, fndecl, depth,
-                 rewind_info)
-  {
-  }
-
-  label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
-};
-
-/* A concrete event subclass for rewinding from a longjmp to a setjmp,
-   showing the setjmp (or sigsetjmp).  */
-
-class rewind_to_setjmp_event : public rewind_event
-{
-public:
-  rewind_to_setjmp_event (const exploded_edge *eedge,
-                         location_t loc, tree fndecl, int depth,
-                         const rewind_info_t *rewind_info)
-  : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc, fndecl, depth,
-                 rewind_info)
-  {
-  }
-
-  label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
-
-  void prepare_for_emission (checker_path *path,
-                            pending_diagnostic *pd,
-                            diagnostic_event_id_t emission_id) FINAL OVERRIDE;
-
-private:
-  diagnostic_event_id_t m_original_setjmp_event_id;
-};
-
-/* Concrete subclass of checker_event for use at the end of a path:
-   a repeat of the warning message at the end of the path (perhaps with
-   references to pertinent events that occurred on the way), at the point
-   where the problem occurs.  */
-
-class warning_event : public checker_event
-{
-public:
-  warning_event (location_t loc, tree fndecl, int depth,
-                const state_machine *sm,
-                tree var, state_machine::state_t state)
-  : checker_event (EK_WARNING, loc, fndecl, depth),
-    m_sm (sm), m_var (var), m_state (state)
-  {
-  }
-
-  label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
-
-private:
-  const state_machine *m_sm;
-  tree m_var;
-  state_machine::state_t m_state;
-};
+namespace ana {
 
 /* Subclass of diagnostic_path for analyzer diagnostics.  */
 
 class checker_path : public diagnostic_path
 {
 public:
-  checker_path () : diagnostic_path () {}
+  checker_path (logger *logger) : diagnostic_path (), m_logger (logger) {}
 
   /* Implementation of diagnostic_path vfuncs.  */
 
-  unsigned num_events () const FINAL OVERRIDE
+  unsigned num_events () const final override
   {
     return m_events.length ();
   }
 
-  const diagnostic_event & get_event (int idx) const FINAL OVERRIDE
+  const diagnostic_event & get_event (int idx) const final override
   {
     return *m_events[idx];
   }
@@ -470,10 +54,7 @@ public:
 
   void maybe_log (logger *logger, const char *desc) const;
 
-  void add_event (checker_event *event)
-  {
-    m_events.safe_push (event);
-  }
+  void add_event (std::unique_ptr<checker_event> event);
 
   void delete_event (int idx)
   {
@@ -482,9 +63,24 @@ public:
     delete event;
   }
 
-  void add_final_event (const state_machine *sm,
-                       const exploded_node *enode, const gimple *stmt,
-                       tree var, state_machine::state_t state);
+  void delete_events (unsigned start_idx, unsigned len)
+  {
+    for (unsigned i = start_idx; i < start_idx + len; i++)
+      delete m_events[i];
+    m_events.block_remove (start_idx, len);
+  }
+
+  void replace_event (unsigned idx, checker_event *new_event)
+  {
+    delete m_events[idx];
+    m_events[idx] = new_event;
+  }
+
+  void add_region_creation_events (pending_diagnostic *pd,
+                                  const region *reg,
+                                  const region_model *model,
+                                  const event_loc_info &loc_info,
+                                  bool debug);
 
   /* After all event-pruning, a hook for notifying each event what
      its ID will be.  The events are notified in order, allowing
@@ -498,6 +94,8 @@ public:
       e->prepare_for_emission (this, pd, diagnostic_event_id_t (i));
   }
 
+  void fixup_locations (pending_diagnostic *pd);
+
   void record_setjmp_event (const exploded_node *enode,
                            diagnostic_event_id_t setjmp_emission_id)
   {
@@ -515,6 +113,10 @@ public:
     return false;
   }
 
+  bool cfg_edge_pair_at_p (unsigned idx) const;
+
+  void inject_any_inlined_call_events (logger *logger);
+
 private:
   DISABLE_COPY_AND_ASSIGN(checker_path);
 
@@ -525,6 +127,8 @@ private:
      exploded_node *, so that rewind events can refer to them in their
      descriptions.  */
   hash_map <const exploded_node *, diagnostic_event_id_t> m_setjmp_event_ids;
+
+  logger *m_logger;
 };
 
 } // namespace ana