GCC Middle and Back End API Reference
diagnostics/digraphs.h
Go to the documentation of this file.
1/* Directed graphs associated with a diagnostic.
2 Copyright (C) 2025-2026 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#ifndef GCC_DIAGNOSTICS_DIGRAPHS_H
22#define GCC_DIAGNOSTICS_DIGRAPHS_H
23
24#include "json.h"
25#include "tristate.h"
27
28class graphviz_out;
29
30class sarif_graph;
31class sarif_node;
32class sarif_edge;
33
34namespace dot { class graph; }
35
36namespace diagnostics {
37namespace digraphs {
38
39/* A family of classes: digraph, node, and edge, closely related to
40 SARIF's graph, node, and edge types (SARIF v2.1.0 sections 3.39-3.41).
41
42 Nodes can have child nodes, allowing for arbitrarily deep nesting.
43 Edges can be between any pair of nodes (potentially at different
44 nesting levels).
45
46 Digraphs, nodes, and edges also optionally have a JSON property bag,
47 allowing round-tripping of arbitrary key/value pairs through SARIF. */
48
49class digraph;
50class node;
51class edge;
52
53/* A base class for digraph, node, and edge to allow them to have
54 an optional JSON property bag. */
55
56class object
57{
58public:
59 /* String properties. */
60 const char *get_property (const json::string_property &property) const;
61 void set_property (const json::string_property &property,
62 const char *utf8_value);
63
64 /* Integer properties. */
65 bool maybe_get_property (const json::integer_property &property, long &out) const;
66 void set_property (const json::integer_property &property, long value);
67
68 /* Bool properties. */
70 get_property_as_tristate (const json::bool_property &property) const;
71 void set_property (const json::bool_property &property, bool value);
72
73 /* Array-of-string properties. */
75 get_property (const json::array_of_string_property &property) const;
76
77 /* enum properties. */
78 template <typename EnumType>
79 EnumType
81 {
83 {
84 EnumType result;
85 if (m_property_bag->maybe_get_enum<EnumType> (property, result))
86 return result;
87 }
89 }
90 template <typename EnumType>
91 void
93 EnumType value)
94 {
95 auto &bag = ensure_property_bag ();
96 bag.set_enum<EnumType> (property, value);
97 }
98
99 /* json::value properties. */
100 const json::value *get_property (const json::json_property &property) const;
101 void set_property (const json::json_property &property,
102 std::unique_ptr<json::value> value);
103
105 get_property_bag () const { return m_property_bag.get (); }
106
109
110 void
111 set_property_bag (std::unique_ptr<json::object> property_bag)
112 {
113 m_property_bag = std::move (property_bag);
114 }
115
116private:
117 std::unique_ptr<json::object> m_property_bag;
118};
119
120// A directed graph, corresponding to SARIF v2.1.0 section 3.39.
121
122class digraph : public object
123{
124 public:
125 friend class node;
126 friend class edge;
127
129 virtual ~digraph () {}
130
131 const char *
133 {
134 if (!m_description)
135 return nullptr;
136 return m_description->c_str ();
137 }
138
139 void
140 set_description (const char *desc)
141 {
142 if (desc)
143 m_description = std::make_unique<std::string> (desc);
144 else
145 m_description = nullptr;
146 }
147 void
148 set_description (std::string desc)
149 {
150 m_description = std::make_unique<std::string> (std::move (desc));
151 }
152
153 node *
154 get_node_by_id (const char *id) const
155 {
156 auto iter = m_id_to_node_map.find (id);
157 if (iter == m_id_to_node_map.end ())
158 return nullptr;
159 return iter->second;
160 }
161
162 edge *
163 get_edge_by_id (const char *id) const
164 {
165 auto iter = m_id_to_edge_map.find (id);
166 if (iter == m_id_to_edge_map.end ())
167 return nullptr;
168 return iter->second;
169 }
170
171 size_t
173 {
174 return m_nodes.size ();
175 }
176
177 node &
178 get_node (size_t idx) const
179 {
180 return *m_nodes[idx].get ();
181 }
182
183 size_t
185 {
186 return m_edges.size ();
187 }
188
189 edge &
190 get_edge (size_t idx) const
191 {
192 return *m_edges[idx].get ();
193 }
194
195 void
196 dump () const;
197
198 std::unique_ptr<json::object>
199 make_json_sarif_graph () const;
200
201 std::unique_ptr<dot::graph>
202 make_dot_graph () const;
203
204 void
205 add_node (std::unique_ptr<node> n)
206 {
207 gcc_assert (n);
208 m_nodes.push_back (std::move (n));
209 }
210
211 void
212 add_edge (std::unique_ptr<edge> e)
213 {
214 gcc_assert (e);
215 m_edges.push_back (std::move (e));
216 }
217
218 void
219 add_edge (const char *id,
220 node &src_node,
221 node &dst_node,
222 const char *label = nullptr);
223
224 std::unique_ptr<digraph> clone () const;
225
226 const char *get_graph_kind () const;
227 void set_graph_kind (const char *);
228
229 const std::map<std::string, node *> &
231 {
232 return m_id_to_node_map;
233 }
234
235 private:
236 void
237 add_node_id (std::string node_id, node &new_node)
238 {
239 m_id_to_node_map.insert ({std::move (node_id), &new_node});
240 }
241 void
242 add_edge_id (std::string edge_id, edge &new_edge)
243 {
244 m_id_to_edge_map.insert ({std::move (edge_id), &new_edge});
245 }
246
247 std::string
248 make_edge_id (const char *edge_id);
249
250 std::unique_ptr<std::string> m_description;
251 std::map<std::string, node *> m_id_to_node_map;
252 std::map<std::string, edge *> m_id_to_edge_map;
253 std::vector<std::unique_ptr<node>> m_nodes;
254 std::vector<std::unique_ptr<edge>> m_edges;
256};
257
258// A node in a directed graph, corresponding to SARIF v2.1.0 section 3.40.
259
260class node : public object
261{
262 public:
263 virtual ~node () {}
264
265 node (digraph &g, std::string id)
266 : m_id (id),
268 {
269 g.add_node_id (std::move (id), *this);
270 }
271 node (const node &) = delete;
272
273 std::string
274 get_id () const { return m_id; }
275
276 const char *
277 get_label () const
278 {
279 if (!m_label)
280 return nullptr;
281 return m_label->c_str ();
282 }
283
284 void
285 set_label (const char *label)
286 {
287 if (label)
288 m_label = std::make_unique<std::string> (label);
289 else
290 m_label = nullptr;
291 }
292 void
293 set_label (std::string label)
294 {
295 m_label = std::make_unique<std::string> (std::move (label));
296 }
297
298 size_t
299 get_num_children () const { return m_children.size (); }
300
301 node &
302 get_child (size_t idx) const { return *m_children[idx].get (); }
303
304 void
305 add_child (std::unique_ptr<node> child)
306 {
307 gcc_assert (child);
308 m_children.push_back (std::move (child));
309 }
310
311 location_t
313 {
314 return m_physical_loc;
315 }
316
317 void
318 set_physical_loc (location_t physical_loc)
319 {
320 m_physical_loc = physical_loc;
321 }
322
325 {
326 return m_logical_loc;
327 }
328
329 void
331 {
332 m_logical_loc = logical_loc;
333 }
334
335 void print (graphviz_out &gv) const;
336
337 void
338 dump () const;
339
340 std::unique_ptr<json::object>
342
343 std::unique_ptr<node>
345 std::map<node *, node *> &node_mapping) const;
346
347private:
348 std::string m_id;
349 std::unique_ptr<std::string> m_label;
350 std::vector<std::unique_ptr<node>> m_children;
351 location_t m_physical_loc;
353};
354
355// An edge in a directed graph, corresponding to SARIF v2.1.0 section 3.41.
356
357class edge : public object
358{
359 public:
360 virtual ~edge () {}
361
362 /* SARIF requires us to provide unique edge IDs within a graph,
363 but otherwise we don't need them.
364 Pass in nullptr for the id to get the graph to generate a unique
365 edge id for us. */
367 const char *id,
368 node &src_node,
369 node &dst_node)
370 : m_id (g.make_edge_id (id)),
371 m_src_node (src_node),
372 m_dst_node (dst_node)
373 {
374 g.add_edge_id (m_id, *this);
375 }
376
377 std::string
378 get_id () const { return m_id; }
379
380 const char *
381 get_label () const
382 {
383 if (!m_label)
384 return nullptr;
385 return m_label->c_str ();
386 }
387
388 void
389 set_label (const char *label)
390 {
391 if (label)
392 m_label = std::make_unique<std::string> (label);
393 else
394 m_label = nullptr;
395 }
396
397 node &
398 get_src_node () const { return m_src_node; }
399
400 node &
401 get_dst_node () const { return m_dst_node; }
402
403 void
404 dump () const;
405
406 std::unique_ptr<json::object>
407 to_json_sarif_edge () const;
408
409 std::unique_ptr<edge>
411 const std::map<diagnostics::digraphs::node *, diagnostics::digraphs::node *> &node_mapping) const;
412
413private:
414 std::string m_id;
415 std::unique_ptr<std::string> m_label;
418};
419
420} // namespace digraphs
421} // namespace diagnostics
422
423#endif /* ! GCC_DIAGNOSTICS_DIGRAPHS_H */
Definition diagnostics/digraphs.h:123
std::unique_ptr< std::string > m_description
Definition diagnostics/digraphs.h:250
digraph()
Definition diagnostics/digraphs.h:128
void set_graph_kind(const char *)
Definition diagnostics/digraphs.cc:244
size_t get_num_edges() const
Definition diagnostics/digraphs.h:184
edge * get_edge_by_id(const char *id) const
Definition diagnostics/digraphs.h:163
friend class edge
Definition diagnostics/digraphs.h:126
const char * get_graph_kind() const
Definition diagnostics/digraphs.cc:238
std::vector< std::unique_ptr< edge > > m_edges
Definition diagnostics/digraphs.h:254
size_t m_next_edge_id_index
Definition diagnostics/digraphs.h:255
std::unique_ptr< digraph > clone() const
Definition diagnostics/digraphs.cc:176
void set_description(std::string desc)
Definition diagnostics/digraphs.h:148
void add_node_id(std::string node_id, node &new_node)
Definition diagnostics/digraphs.h:237
std::unique_ptr< json::object > make_json_sarif_graph() const
Definition diagnostics/digraphs.cc:163
std::unique_ptr< dot::graph > make_dot_graph() const
Definition diagnostics/digraphs.cc:169
node * get_node_by_id(const char *id) const
Definition diagnostics/digraphs.h:154
void add_node(std::unique_ptr< node > n)
Definition diagnostics/digraphs.h:205
void dump() const
Definition diagnostics/digraphs.cc:157
void add_edge_id(std::string edge_id, edge &new_edge)
Definition diagnostics/digraphs.h:242
std::map< std::string, node * > m_id_to_node_map
Definition diagnostics/digraphs.h:251
std::string make_edge_id(const char *edge_id)
Definition diagnostics/digraphs.cc:216
const std::map< std::string, node * > & get_all_nodes() const
Definition diagnostics/digraphs.h:230
const char * get_description() const
Definition diagnostics/digraphs.h:132
edge & get_edge(size_t idx) const
Definition diagnostics/digraphs.h:190
size_t get_num_nodes() const
Definition diagnostics/digraphs.h:172
virtual ~digraph()
Definition diagnostics/digraphs.h:129
std::vector< std::unique_ptr< node > > m_nodes
Definition diagnostics/digraphs.h:253
void add_edge(std::unique_ptr< edge > e)
Definition diagnostics/digraphs.h:212
std::map< std::string, edge * > m_id_to_edge_map
Definition diagnostics/digraphs.h:252
node & get_node(size_t idx) const
Definition diagnostics/digraphs.h:178
void set_description(const char *desc)
Definition diagnostics/digraphs.h:140
Definition diagnostics/digraphs.h:358
edge(digraph &g, const char *id, node &src_node, node &dst_node)
Definition diagnostics/digraphs.h:366
std::string get_id() const
Definition diagnostics/digraphs.h:378
node & m_src_node
Definition diagnostics/digraphs.h:416
virtual ~edge()
Definition diagnostics/digraphs.h:360
std::string m_id
Definition diagnostics/digraphs.h:414
void dump() const
Definition diagnostics/digraphs.cc:304
node & get_dst_node() const
Definition diagnostics/digraphs.h:401
node & m_dst_node
Definition diagnostics/digraphs.h:417
std::unique_ptr< edge > clone(digraph &new_graph, const std::map< diagnostics::digraphs::node *, diagnostics::digraphs::node * > &node_mapping) const
std::unique_ptr< json::object > to_json_sarif_edge() const
Definition diagnostics/digraphs.cc:310
std::unique_ptr< std::string > m_label
Definition diagnostics/digraphs.h:415
void set_label(const char *label)
Definition diagnostics/digraphs.h:389
const char * get_label() const
Definition diagnostics/digraphs.h:381
node & get_src_node() const
Definition diagnostics/digraphs.h:398
Definition diagnostics/digraphs.h:261
std::unique_ptr< json::object > to_json_sarif_node() const
std::string get_id() const
Definition diagnostics/digraphs.h:274
void add_child(std::unique_ptr< node > child)
Definition diagnostics/digraphs.h:305
void set_label(std::string label)
Definition diagnostics/digraphs.h:293
std::unique_ptr< std::string > m_label
Definition diagnostics/digraphs.h:349
node(const node &)=delete
std::unique_ptr< node > clone(digraph &new_graph, std::map< node *, node * > &node_mapping) const
std::vector< std::unique_ptr< node > > m_children
Definition diagnostics/digraphs.h:350
location_t get_physical_loc() const
Definition diagnostics/digraphs.h:312
logical_locations::key get_logical_loc() const
Definition diagnostics/digraphs.h:324
std::string m_id
Definition diagnostics/digraphs.h:348
void set_physical_loc(location_t physical_loc)
Definition diagnostics/digraphs.h:318
void set_label(const char *label)
Definition diagnostics/digraphs.h:285
size_t get_num_children() const
Definition diagnostics/digraphs.h:299
void print(graphviz_out &gv) const
const char * get_label() const
Definition diagnostics/digraphs.h:277
node(digraph &g, std::string id)
Definition diagnostics/digraphs.h:265
virtual ~node()
Definition diagnostics/digraphs.h:263
node & get_child(size_t idx) const
Definition diagnostics/digraphs.h:302
location_t m_physical_loc
Definition diagnostics/digraphs.h:351
logical_locations::key m_logical_loc
Definition diagnostics/digraphs.h:352
void set_logical_loc(logical_locations::key logical_loc)
Definition diagnostics/digraphs.h:330
Definition diagnostics/digraphs.h:57
tristate get_property_as_tristate(const json::bool_property &property) const
Definition diagnostics/digraphs.cc:100
const char * get_property(const json::string_property &property) const
Definition diagnostics/digraphs.cc:48
void set_property(const json::enum_property< EnumType > &property, EnumType value)
Definition diagnostics/digraphs.h:92
bool maybe_get_property(const json::integer_property &property, long &out) const
Definition diagnostics/digraphs.cc:69
void set_property_bag(std::unique_ptr< json::object > property_bag)
Definition diagnostics/digraphs.h:111
json::object * get_property_bag() const
Definition diagnostics/digraphs.h:105
std::unique_ptr< json::object > m_property_bag
Definition diagnostics/digraphs.h:117
json::object & ensure_property_bag()
Definition diagnostics/digraphs.cc:147
EnumType get_property(const json::enum_property< EnumType > &property) const
Definition diagnostics/digraphs.h:80
void set_property(const json::string_property &property, const char *utf8_value)
Definition diagnostics/digraphs.cc:59
Definition logical-locations.h:101
Definition graphviz.h:388
Definition json.h:259
Definition json.h:188
Definition json.h:159
Definition tristate.h:26
gcc::context * g
Definition context.cc:31
struct graph * new_graph(int n_vertices)
Definition graphds.cc:50
#define UNKNOWN_LOCATION
Definition input.h:32
Definition custom-sarif-properties/state-graphs.h:33
Definition diagnostics/context.h:39
Definition cfghooks.h:26
Definition graphviz.cc:147
property< literal > bool_property
Definition json.h:139
property< value > json_property
Definition json.h:140
property< integer_number > integer_property
Definition json.h:138
property< array > array_of_string_property
Definition json.h:141
property< string > string_property
Definition json.h:137
property< enum_traits< EnumType > > enum_property
Definition json.h:154
Definition graphviz.h:160
Definition collect2.cc:168
static enum_t get_unknown_value()
#define gcc_assert(EXPR)
Definition system.h:817