| /* Extensions to diagnostics::digraphs to support state graphs. |
| Copyright (C) 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/>. */ |
| |
| #define INCLUDE_ALGORITHM |
| #define INCLUDE_MAP |
| #define INCLUDE_SET |
| #define INCLUDE_STRING |
| #define INCLUDE_VECTOR |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| |
| #include "diagnostics/state-graphs.h" |
| #include "selftest.h" |
| |
| using namespace diagnostics::state_graphs; |
| |
| const char * const node_kind_strs[] = { |
| "globals", |
| "code", |
| "function", |
| "stack", |
| "stack-frame", |
| "heap", |
| "thread-local", |
| "dynalloc-buffer", |
| "variable", |
| "field", |
| "padding", |
| "element", |
| "other", |
| }; |
| |
| const char * |
| diagnostics::state_graphs::node_kind_to_str (enum node_kind k) |
| { |
| return node_kind_strs[static_cast<int> (k)]; |
| } |
| |
| // struct state_node_ref |
| |
| enum node_kind |
| state_node_ref::get_node_kind () const |
| { |
| const char *value = get_attr ("kind"); |
| if (!value) |
| return node_kind::other; |
| |
| for (size_t i = 0; i < ARRAY_SIZE (node_kind_strs); ++i) |
| if (!strcmp (node_kind_strs[i], value)) |
| return static_cast<enum node_kind> (i); |
| |
| return node_kind::other; |
| } |
| |
| void |
| state_node_ref::set_node_kind (enum node_kind k) |
| { |
| set_attr ("kind", node_kind_to_str (k)); |
| } |
| |
| const char * const dynalloc_state_strs[] = { |
| "unknown", |
| "nonnull", |
| "unchecked", |
| "freed" |
| }; |
| |
| enum node_dynalloc_state |
| state_node_ref::get_dynalloc_state () const |
| { |
| const char *value = get_attr ("dynalloc-state"); |
| if (!value) |
| return node_dynalloc_state::unknown; |
| |
| for (size_t i = 0; i < ARRAY_SIZE (dynalloc_state_strs); ++i) |
| if (!strcmp (dynalloc_state_strs[i], value)) |
| return static_cast<enum node_dynalloc_state> (i); |
| |
| return node_dynalloc_state::unknown; |
| } |
| |
| void |
| state_node_ref::set_dynalloc_state (enum node_dynalloc_state s) const |
| { |
| set_attr ("dynalloc-state", |
| dynalloc_state_strs[static_cast <size_t> (s)]); |
| } |
| |
| const char * |
| state_node_ref::get_dynamic_extents () const |
| { |
| return m_node.get_attr (STATE_NODE_PREFIX, "dynamic-extents"); |
| } |
| |
| void |
| state_node_ref::set_json_attr (const char *key, |
| std::unique_ptr<json::value> value) const |
| { |
| m_node.set_json_attr (STATE_NODE_PREFIX, key, std::move (value)); |
| } |
| |
| #if CHECKING_P |
| |
| namespace diagnostics { |
| namespace selftest { |
| |
| static void |
| test_node_attrs () |
| { |
| digraphs::digraph g; |
| digraphs::node n (g, "a"); |
| state_node_ref node_ref (n); |
| |
| ASSERT_EQ (node_ref.get_node_kind (), node_kind::other); |
| node_ref.set_node_kind (node_kind::stack); |
| ASSERT_EQ (node_ref.get_node_kind (), node_kind::stack); |
| |
| ASSERT_EQ (node_ref.get_dynalloc_state (), node_dynalloc_state::unknown); |
| node_ref.set_dynalloc_state (node_dynalloc_state::freed); |
| ASSERT_EQ (node_ref.get_dynalloc_state (), node_dynalloc_state::freed); |
| |
| ASSERT_EQ (node_ref.get_type (), nullptr); |
| node_ref.set_type ("const char *"); |
| ASSERT_STREQ (node_ref.get_type (), "const char *"); |
| } |
| |
| /* Run all of the selftests within this file. */ |
| |
| void |
| state_graphs_cc_tests () |
| { |
| test_node_attrs (); |
| } |
| |
| } // namespace diagnostics::selftest |
| } // namespace diagnostics |
| |
| #endif /* CHECKING_P */ |