]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/analyzer/checker-path.h
Update copyright years.
[thirdparty/gcc.git] / gcc / analyzer / checker-path.h
index c8de5c9be2c7cf8777b88d3b4c8ca7c8394771e4..6b3e8a34fe561a179bd60454c28e50cfc06ef429 100644 (file)
@@ -1,5 +1,5 @@
-/* Subclasses of diagnostic_path and diagnostic_event for analyzer diagnostics.
-   Copyright (C) 2019-2022 Free Software Foundation, Inc.
+/* Subclass of diagnostic_path for analyzer diagnostics.
+   Copyright (C) 2019-2024 Free Software Foundation, Inc.
    Contributed by David Malcolm <dmalcolm@redhat.com>.
 
 This file is part of GCC.
@@ -21,593 +21,20 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_ANALYZER_CHECKER_PATH_H
 #define GCC_ANALYZER_CHECKER_PATH_H
 
-#include "tree-logical-location.h"
+#include "analyzer/checker-event.h"
 
 namespace ana {
 
-/* An enum for discriminating between the concrete subclasses of
-   checker_event.  */
-
-enum event_kind
-{
-  EK_DEBUG,
-  EK_CUSTOM,
-  EK_STMT,
-  EK_REGION_CREATION,
-  EK_FUNCTION_ENTRY,
-  EK_STATE_CHANGE,
-  EK_START_CFG_EDGE,
-  EK_END_CFG_EDGE,
-  EK_CALL_EDGE,
-  EK_RETURN_EDGE,
-  EK_START_CONSOLIDATED_CFG_EDGES,
-  EK_END_CONSOLIDATED_CFG_EDGES,
-  EK_INLINED_CALL,
-  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)
-        precanned_custom_event
-       statement_event (EK_STMT)
-       region_creation_event (EK_REGION_CREATION)
-       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)
-       start_consolidated_cfg_edges_event (EK_START_CONSOLIDATED_CFG_EDGES)
-       end_consolidated_cfg_edges_event (EK_END_CONSOLIDATED_CFG_EDGES)
-       inlined_call_event (EK_INLINED_CALL)
-       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:
-  /* Implementation of diagnostic_event.  */
-
-  location_t get_location () const final override { return m_loc; }
-  tree get_fndecl () const final override { return m_effective_fndecl; }
-  int get_stack_depth () const final override { return m_effective_depth; }
-  const logical_location *get_logical_location () const final override
-  {
-    if (m_effective_fndecl)
-      return &m_logical_loc;
-    else
-      return NULL;
-  }
-  meaning get_meaning () const override;
-
-  /* Additional functionality.  */
-
-  int get_original_stack_depth () const { return m_original_depth; }
-
-  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; }
-
-  /* For use with %@.  */
-  const diagnostic_event_id_t *get_id_ptr () const
-  {
-    return &m_emission_id;
-  }
-
-  void dump (pretty_printer *pp) const;
-
-  void set_location (location_t loc) { m_loc = loc; }
-
-protected:
-  checker_event (enum event_kind kind,
-                location_t loc, tree fndecl, int depth);
-
- public:
-  const enum event_kind m_kind;
- protected:
-  location_t m_loc;
-  tree m_original_fndecl;
-  tree m_effective_fndecl;
-  int m_original_depth;
-  int m_effective_depth;
-  pending_diagnostic *m_pending_diagnostic;
-  diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
-  tree_logical_location m_logical_loc;
-};
-
-/* 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;
-};
-
-/* An abstract 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
-{
-protected:
-  custom_event (location_t loc, tree fndecl, int depth)
-  : checker_event (EK_CUSTOM, loc, fndecl, depth)
-  {
-  }
-};
-
-/* A concrete custom_event subclass with a precanned message.  */
-
-class precanned_custom_event : public custom_event
-{
-public:
-  precanned_custom_event (location_t loc, tree fndecl, int depth,
-                         const char *desc)
-  : custom_event (loc, fndecl, depth),
-    m_desc (xstrdup (desc))
-  {
-  }
-  ~precanned_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;
-};
-
-/* There are too many combinations to express region creation in one message,
-   so we emit multiple region_creation_event instances when each pertinent
-   region is created.
-
-   This enum distinguishes between the different messages.  */
-
-enum rce_kind
-{
-  /* Generate a message based on the memory space of the region
-     e.g. "region created on stack here".  */
-  RCE_MEM_SPACE,
-
-  /* Generate a message based on the capacity of the region
-     e.g. "capacity: 100 bytes".  */
-  RCE_CAPACITY,
-
-  /* Generate a debug message.  */
-  RCE_DEBUG
-};
-
-/* A concrete event subclass describing the creation of a region that
-   is significant for a diagnostic.  */
-
-class region_creation_event : public checker_event
-{
-public:
-  region_creation_event (const region *reg,
-                        tree capacity,
-                        enum rce_kind kind,
-                        location_t loc, tree fndecl, int depth);
-
-  label_text get_desc (bool can_colorize) const final override;
-
-private:
-  const region *m_reg;
-  tree m_capacity;
-  enum rce_kind m_rce_kind;
-};
-
-/* 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;
-  meaning get_meaning () const 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;
-  meaning get_meaning () const 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;
-};
-
-/* 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:
-  meaning get_meaning () const override;
-
-  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 override;
-  meaning get_meaning () const override;
-
-  bool is_call_p () const final override;
-
-protected:
-  tree get_caller_fndecl () const;
-  tree get_callee_fndecl () const;
-
-  const supernode *m_src_snode;
-  const supernode *m_dest_snode;
-};
-
-/* 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;
-  meaning get_meaning () const override;
-
-  bool is_return_p () const final override;
-
-  const supernode *m_src_snode;
-  const supernode *m_dest_snode;
-};
-
-/* A concrete event subclass for the start of a consolidated run of CFG
-   edges all either TRUE or FALSE e.g. "following 'false' branch...'.  */
-
-class start_consolidated_cfg_edges_event : public checker_event
-{
-public:
-  start_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth,
-                                     bool edge_sense)
-  : checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth),
-    m_edge_sense (edge_sense)
-  {
-  }
-
-  label_text get_desc (bool can_colorize) const final override;
-  meaning get_meaning () const override;
-
- private:
-  bool m_edge_sense;
-};
-
-/* A concrete event subclass for the end of a consolidated run of
-   CFG edges e.g. "...to here'.  */
-
-class end_consolidated_cfg_edges_event : public checker_event
-{
-public:
-  end_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth)
-  : checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth)
-  {
-  }
-
-  label_text get_desc (bool /*can_colorize*/) const final override
-  {
-    return label_text::borrow ("...to here");
-  }
-};
-
-/* A concrete event subclass for describing an inlined call event
-   e.g. "inlined call to 'callee' from 'caller'".  */
-
-class inlined_call_event : public checker_event
-{
-public:
-  inlined_call_event (location_t loc,
-                     tree apparent_callee_fndecl,
-                     tree apparent_caller_fndecl,
-                     int actual_depth,
-                     int stack_depth_adjustment)
-  : checker_event (EK_INLINED_CALL, loc,
-                  apparent_caller_fndecl,
-                  actual_depth + stack_depth_adjustment),
-    m_apparent_callee_fndecl (apparent_callee_fndecl),
-    m_apparent_caller_fndecl (apparent_caller_fndecl)
-  {
-    gcc_assert (LOCATION_BLOCK (loc) == NULL);
-  }
-
-  label_text get_desc (bool /*can_colorize*/) const final override;
-  meaning get_meaning () const override;
-
-private:
-  tree m_apparent_callee_fndecl;
-  tree m_apparent_caller_fndecl;
-};
-
-/* 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;
-  meaning get_meaning () const override;
-
-private:
-  const state_machine *m_sm;
-  tree m_var;
-  state_machine::state_t m_state;
-};
-
 /* 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_thread ("main"),
+    m_logger (logger)
+  {}
 
   /* Implementation of diagnostic_path vfuncs.  */
 
@@ -620,6 +47,15 @@ public:
   {
     return *m_events[idx];
   }
+  unsigned num_threads () const final override
+  {
+    return 1;
+  }
+  const diagnostic_thread &
+  get_thread (diagnostic_thread_id_t) const final override
+  {
+    return m_thread;
+  }
 
   checker_event *get_checker_event (int idx)
   {
@@ -629,12 +65,10 @@ public:
   void dump (pretty_printer *pp) const;
   void debug () const;
 
+  logger *get_logger () const { return m_logger; }
   void maybe_log (logger *logger, const char *desc) const;
 
-  void add_event (std::unique_ptr<checker_event> event)
-  {
-    m_events.safe_push (event.release ());
-  }
+  void add_event (std::unique_ptr<checker_event> event);
 
   void delete_event (int idx)
   {
@@ -656,16 +90,12 @@ public:
     m_events[idx] = new_event;
   }
 
-  void add_region_creation_events (const region *reg,
+  void add_region_creation_events (pending_diagnostic *pd,
+                                  const region *reg,
                                   const region_model *model,
-                                  location_t loc,
-                                  tree fndecl, int depth,
+                                  const event_loc_info &loc_info,
                                   bool debug);
 
-  void add_final_event (const state_machine *sm,
-                       const exploded_node *enode, const gimple *stmt,
-                       tree var, state_machine::state_t state);
-
   /* After all event-pruning, a hook for notifying each event what
      its ID will be.  The events are notified in order, allowing
      for later events to refer to the IDs of earlier events in
@@ -704,6 +134,8 @@ public:
 private:
   DISABLE_COPY_AND_ASSIGN(checker_path);
 
+  simple_diagnostic_thread m_thread;
+
   /* The events that have occurred along this path.  */
   auto_delete_vec<checker_event> m_events;
 
@@ -711,6 +143,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