aboutsummaryrefslogtreecommitdiff
path: root/gcc/diagnostics/paths.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/diagnostics/paths.h')
-rw-r--r--gcc/diagnostics/paths.h250
1 files changed, 250 insertions, 0 deletions
diff --git a/gcc/diagnostics/paths.h b/gcc/diagnostics/paths.h
new file mode 100644
index 0000000..d30c420
--- /dev/null
+++ b/gcc/diagnostics/paths.h
@@ -0,0 +1,250 @@
+/* Paths through the code associated with a diagnostic.
+ Copyright (C) 2019-2025 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_DIAGNOSTICS_PATHS_H
+#define GCC_DIAGNOSTICS_PATHS_H
+
+#include "diagnostic.h" /* for ATTRIBUTE_GCC_DIAG. */
+#include "diagnostics/event-id.h"
+#include "diagnostics/logical-locations.h"
+
+namespace diagnostics {
+ namespace digraphs {
+ class digraph;
+ } // namespace digraphs
+ namespace logical_locations {
+ class manager;
+ } // logical_locations
+ class sarif_builder;
+ class sarif_object;
+} //namespace diagnostics
+
+namespace diagnostics {
+namespace paths {
+
+/* A diagnostics::paths::path is an optional additional piece of metadata associated
+ with a diagnostic (via its rich_location).
+
+ It describes a sequence of events predicted by the compiler that
+ lead to the problem occurring, with their locations in the user's source,
+ and text descriptions.
+
+ For example, the following error has a 3-event path:
+
+ test.c: In function 'demo':
+ test.c:29:5: error: passing NULL as argument 1 to 'PyList_Append' which
+ requires a non-NULL parameter
+ 29 | PyList_Append(list, item);
+ | ^~~~~~~~~~~~~~~~~~~~~~~~~
+ 'demo': events 1-3
+ 25 | list = PyList_New(0);
+ | ^~~~~~~~~~~~~
+ | |
+ | (1) when 'PyList_New' fails, returning NULL
+ 26 |
+ 27 | for (i = 0; i < count; i++) {
+ | ~~~
+ | |
+ | (2) when 'i < count'
+ 28 | item = PyLong_FromLong(random());
+ 29 | PyList_Append(list, item);
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~
+ | |
+ | (3) when calling 'PyList_Append', passing NULL from (1) as argument 1
+
+ The diagnostic-printing code has consolidated the path into a single
+ run of events, since all the events are near each other and within the same
+ function; more complicated examples (such as interprocedural paths)
+ might be printed as multiple runs of events. */
+
+/* Abstract base classes, describing events within a path, and the paths
+ themselves. */
+
+/* One event within a path. */
+
+class event
+{
+ public:
+ /* Enums for giving a sense of what this event means.
+ Roughly corresponds to SARIF v2.1.0 section 3.38.8. */
+ enum class verb
+ {
+ unknown,
+
+ acquire,
+ release,
+ enter,
+ exit,
+ call,
+ return_,
+ branch,
+
+ danger
+ };
+ enum class noun
+ {
+ unknown,
+
+ taint,
+ sensitive, // this one isn't in SARIF v2.1.0; filed as https://github.com/oasis-tcs/sarif-spec/issues/530
+ function,
+ lock,
+ memory,
+ resource
+ };
+ enum class property
+ {
+ unknown,
+
+ true_,
+ false_
+ };
+ /* A bundle of such enums, allowing for descriptions of the meaning of
+ an event, such as
+ - "acquire memory": meaning (verb::acquire, noun::memory)
+ - "take true branch"": meaning (verb::branch, property::true)
+ - "return from function": meaning (verb::return, noun::function)
+ etc, as per SARIF's threadFlowLocation "kinds" property
+ (SARIF v2.1.0 section 3.38.8). */
+ struct meaning
+ {
+ meaning ()
+ : m_verb (verb::unknown),
+ m_noun (noun::unknown),
+ m_property (property::unknown)
+ {
+ }
+ meaning (enum verb verb, enum noun noun)
+ : m_verb (verb), m_noun (noun), m_property (property::unknown)
+ {
+ }
+ meaning (enum verb verb, enum property property)
+ : m_verb (verb), m_noun (noun::unknown), m_property (property)
+ {
+ }
+
+ void dump_to_pp (pretty_printer *pp) const;
+
+ static const char *maybe_get_verb_str (enum verb);
+ static const char *maybe_get_noun_str (enum noun);
+ static const char *maybe_get_property_str (enum property);
+
+ enum verb m_verb;
+ enum noun m_noun;
+ enum property m_property;
+ };
+
+ virtual ~event () {}
+
+ virtual location_t get_location () const = 0;
+
+ /* Stack depth, so that consumers can visualize the interprocedural
+ calls, returns, and frame nesting. */
+ virtual int get_stack_depth () const = 0;
+
+ /* Print a localized (and possibly colorized) description of this event. */
+ virtual void print_desc (pretty_printer &pp) const = 0;
+
+ /* Get a logical location for this event, or null if there is none. */
+ virtual logical_locations::key get_logical_location () const = 0;
+
+ virtual meaning get_meaning () const = 0;
+
+ /* True iff we should draw a line connecting this event to the
+ next event (e.g. to highlight control flow). */
+ virtual bool connect_to_next_event_p () const = 0;
+
+ virtual thread_id_t get_thread_id () const = 0;
+
+ /* Hook for SARIF output to allow for adding diagnostic-specific
+ properties to the threadFlowLocation object's property bag. */
+ virtual void
+ maybe_add_sarif_properties (sarif_builder &,
+ sarif_object &/*thread_flow_loc_obj*/) const
+ {
+ }
+
+ /* Hook for capturing state at this event, potentially for visualizing
+ in HTML output, or for adding to SARIF. */
+ virtual std::unique_ptr<digraphs::digraph>
+ maybe_make_diagnostic_state_graph (bool debug) const;
+
+ label_text get_desc (pretty_printer &ref_pp) const;
+};
+
+/* Abstract base class representing a thread of execution within
+ a diagnostics::paths::path.
+ Each event is associated with one thread.
+ Typically there is just one thread per diagnostics::paths::path. */
+
+class thread
+{
+public:
+ virtual ~thread () {}
+ virtual label_text get_name (bool can_colorize) const = 0;
+};
+
+/* Abstract base class for getting at a sequence of events. */
+
+class path
+{
+ public:
+ virtual ~path () {}
+ virtual unsigned num_events () const = 0;
+ virtual const event & get_event (int idx) const = 0;
+ virtual unsigned num_threads () const = 0;
+ virtual const thread &
+ get_thread (thread_id_t) const = 0;
+
+ /* Return true iff the two events are both within the same function,
+ or both outside of any function. */
+ virtual bool
+ same_function_p (int event_idx_a,
+ int event_idx_b) const = 0;
+
+ bool interprocedural_p () const;
+ bool multithreaded_p () const;
+
+ const logical_locations::manager &get_logical_location_manager () const
+ {
+ return m_logical_loc_mgr;
+ }
+
+protected:
+ path (const logical_locations::manager &logical_loc_mgr)
+ : m_logical_loc_mgr (logical_loc_mgr)
+ {
+ }
+
+private:
+ bool get_first_event_in_a_function (unsigned *out_idx) const;
+
+ const logical_locations::manager &m_logical_loc_mgr;
+};
+
+} // namespace paths
+} // namespace diagnostics
+
+/* Concrete subclasses of the above can be found in
+ simple-diagnostic-path.h. */
+
+extern void debug (diagnostics::paths::path *path);
+
+#endif /* ! GCC_DIAGNOSTICS_PATHS_H */