(root)/
gcc-13.2.0/
gcc/
diagnostic-path.h
       1  /* Paths through the code associated with a diagnostic.
       2     Copyright (C) 2019-2023 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 under
       8  the terms of the GNU General Public License as published by the Free
       9  Software Foundation; either version 3, or (at your option) any later
      10  version.
      11  
      12  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13  WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15  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  #ifndef GCC_DIAGNOSTIC_PATH_H
      22  #define GCC_DIAGNOSTIC_PATH_H
      23  
      24  #include "diagnostic.h" /* for ATTRIBUTE_GCC_DIAG.  */
      25  #include "diagnostic-event-id.h"
      26  
      27  /* A diagnostic_path is an optional additional piece of metadata associated
      28     with a diagnostic (via its rich_location).
      29  
      30     It describes a sequence of events predicted by the compiler that
      31     lead to the problem occurring, with their locations in the user's source,
      32     and text descriptions.
      33  
      34     For example, the following error has a 3-event path:
      35  
      36       test.c: In function 'demo':
      37       test.c:29:5: error: passing NULL as argument 1 to 'PyList_Append' which
      38         requires a non-NULL parameter
      39          29 |     PyList_Append(list, item);
      40             |     ^~~~~~~~~~~~~~~~~~~~~~~~~
      41         'demo': events 1-3
      42            |
      43            |   25 |   list = PyList_New(0);
      44            |      |          ^~~~~~~~~~~~~
      45            |      |          |
      46            |      |          (1) when 'PyList_New' fails, returning NULL
      47            |   26 |
      48            |   27 |   for (i = 0; i < count; i++) {
      49            |      |   ~~~
      50            |      |   |
      51            |      |   (2) when 'i < count'
      52            |   28 |     item = PyLong_FromLong(random());
      53            |   29 |     PyList_Append(list, item);
      54            |      |     ~~~~~~~~~~~~~~~~~~~~~~~~~
      55            |      |     |
      56            |      |     (3) when calling 'PyList_Append', passing NULL from (1) as argument 1
      57            |
      58  
      59      The diagnostic-printing code has consolidated the path into a single
      60      run of events, since all the events are near each other and within the same
      61      function; more complicated examples (such as interprocedural paths)
      62      might be printed as multiple runs of events.  */
      63  
      64  /* Abstract base classes, describing events within a path, and the paths
      65     themselves.  */
      66  
      67  /* One event within a diagnostic_path.  */
      68  
      69  class diagnostic_event
      70  {
      71   public:
      72    /* Enums for giving a sense of what this event means.
      73       Roughly corresponds to SARIF v2.1.0 section 3.38.8.  */
      74    enum verb
      75    {
      76      VERB_unknown,
      77  
      78      VERB_acquire,
      79      VERB_release,
      80      VERB_enter,
      81      VERB_exit,
      82      VERB_call,
      83      VERB_return,
      84      VERB_branch,
      85  
      86      VERB_danger
      87    };
      88    enum noun
      89    {
      90      NOUN_unknown,
      91  
      92      NOUN_taint,
      93      NOUN_sensitive, // this one isn't in SARIF v2.1.0; filed as https://github.com/oasis-tcs/sarif-spec/issues/530
      94      NOUN_function,
      95      NOUN_lock,
      96      NOUN_memory,
      97      NOUN_resource
      98    };
      99    enum property
     100    {
     101      PROPERTY_unknown,
     102  
     103      PROPERTY_true,
     104      PROPERTY_false
     105    };
     106    /* A bundle of such enums, allowing for descriptions of the meaning of
     107       an event, such as
     108       - "acquire memory": meaning (VERB_acquire, NOUN_memory)
     109       - "take true branch"": meaning (VERB_branch, PROPERTY_true)
     110       - "return from function": meaning (VERB_return, NOUN_function)
     111       etc, as per SARIF's threadFlowLocation "kinds" property
     112       (SARIF v2.1.0 section 3.38.8).  */
     113    struct meaning
     114    {
     115      meaning ()
     116      : m_verb (VERB_unknown),
     117        m_noun (NOUN_unknown),
     118        m_property (PROPERTY_unknown)
     119      {
     120      }
     121      meaning (enum verb verb, enum noun noun)
     122      : m_verb (verb), m_noun (noun), m_property (PROPERTY_unknown)
     123      {
     124      }
     125      meaning (enum verb verb, enum property property)
     126      : m_verb (verb), m_noun (NOUN_unknown), m_property (property)
     127      {
     128      }
     129  
     130      void dump_to_pp (pretty_printer *pp) const;
     131  
     132      static const char *maybe_get_verb_str (enum verb);
     133      static const char *maybe_get_noun_str (enum noun);
     134      static const char *maybe_get_property_str (enum property);
     135  
     136      enum verb m_verb;
     137      enum noun m_noun;
     138      enum property m_property;
     139    };
     140  
     141    virtual ~diagnostic_event () {}
     142  
     143    virtual location_t get_location () const = 0;
     144  
     145    virtual tree get_fndecl () const = 0;
     146  
     147    /* Stack depth, so that consumers can visualizes the interprocedural
     148       calls, returns, and frame nesting.  */
     149    virtual int get_stack_depth () const = 0;
     150  
     151    /* Get a localized (and possibly colorized) description of this event.  */
     152    virtual label_text get_desc (bool can_colorize) const = 0;
     153  
     154    /* Get a logical_location for this event, or NULL.  */
     155    virtual const logical_location *get_logical_location () const = 0;
     156  
     157    virtual meaning get_meaning () const = 0;
     158  };
     159  
     160  /* Abstract base class for getting at a sequence of events.  */
     161  
     162  class diagnostic_path
     163  {
     164   public:
     165    virtual ~diagnostic_path () {}
     166    virtual unsigned num_events () const = 0;
     167    virtual const diagnostic_event & get_event (int idx) const = 0;
     168  
     169    bool interprocedural_p () const;
     170  
     171  private:
     172    bool get_first_event_in_a_function (unsigned *out_idx) const;
     173  };
     174  
     175  /* Concrete subclasses.  */
     176  
     177  /* A simple implementation of diagnostic_event.  */
     178  
     179  class simple_diagnostic_event : public diagnostic_event
     180  {
     181   public:
     182    simple_diagnostic_event (location_t loc, tree fndecl, int depth,
     183  			   const char *desc);
     184    ~simple_diagnostic_event ();
     185  
     186    location_t get_location () const final override { return m_loc; }
     187    tree get_fndecl () const final override { return m_fndecl; }
     188    int get_stack_depth () const final override { return m_depth; }
     189    label_text get_desc (bool) const final override
     190    {
     191      return label_text::borrow (m_desc);
     192    }
     193    const logical_location *get_logical_location () const final override
     194    {
     195      return NULL;
     196    }
     197    meaning get_meaning () const final override
     198    {
     199      return meaning ();
     200    }
     201  
     202   private:
     203    location_t m_loc;
     204    tree m_fndecl;
     205    int m_depth;
     206    char *m_desc; // has been i18n-ed and formatted
     207  };
     208  
     209  /* A simple implementation of diagnostic_path, as a vector of
     210     simple_diagnostic_event instances.  */
     211  
     212  class simple_diagnostic_path : public diagnostic_path
     213  {
     214   public:
     215    simple_diagnostic_path (pretty_printer *event_pp)
     216    : m_event_pp (event_pp) {}
     217  
     218    unsigned num_events () const final override;
     219    const diagnostic_event & get_event (int idx) const final override;
     220  
     221    diagnostic_event_id_t add_event (location_t loc, tree fndecl, int depth,
     222  				   const char *fmt, ...)
     223      ATTRIBUTE_GCC_DIAG(5,6);
     224  
     225   private:
     226    auto_delete_vec<simple_diagnostic_event> m_events;
     227  
     228    /* (for use by add_event).  */
     229    pretty_printer *m_event_pp;
     230  };
     231  
     232  extern void debug (diagnostic_path *path);
     233  
     234  #endif /* ! GCC_DIAGNOSTIC_PATH_H */