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 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 private:
230 void
231 add_node_id (std::string node_id, node &new_node)
232 {
233 m_id_to_node_map.insert ({std::move (node_id), &new_node});
234 }
235 void
236 add_edge_id (std::string edge_id, edge &new_edge)
237 {
238 m_id_to_edge_map.insert ({std::move (edge_id), &new_edge});
239 }
240
241 std::string
242 make_edge_id (const char *edge_id);
243
244 std::unique_ptr<std::string> m_description;
245 std::map<std::string, node *> m_id_to_node_map;
246 std::map<std::string, edge *> m_id_to_edge_map;
247 std::vector<std::unique_ptr<node>> m_nodes;
248 std::vector<std::unique_ptr<edge>> m_edges;
250};
251
252// A node in a directed graph, corresponding to SARIF v2.1.0 section 3.40.
253
254class node : public object
255{
256 public:
257 virtual ~node () {}
258
259 node (digraph &g, std::string id)
260 : m_id (id),
262 {
263 g.add_node_id (std::move (id), *this);
264 }
265 node (const node &) = delete;
266
267 std::string
268 get_id () const { return m_id; }
269
270 const char *
271 get_label () const
272 {
273 if (!m_label)
274 return nullptr;
275 return m_label->c_str ();
276 }
277
278 void
279 set_label (const char *label)
280 {
281 if (label)
282 m_label = std::make_unique<std::string> (label);
283 else
284 m_label = nullptr;
285 }
286 void
287 set_label (std::string label)
288 {
289 m_label = std::make_unique<std::string> (std::move (label));
290 }
291
292 size_t
293 get_num_children () const { return m_children.size (); }
294
295 node &
296 get_child (size_t idx) const { return *m_children[idx].get (); }
297
298 void
299 add_child (std::unique_ptr<node> child)
300 {
301 gcc_assert (child);
302 m_children.push_back (std::move (child));
303 }
304
305 location_t
307 {
308 return m_physical_loc;
309 }
310
311 void
312 set_physical_loc (location_t physical_loc)
313 {
314 m_physical_loc = physical_loc;
315 }
316
319 {
320 return m_logical_loc;
321 }
322
323 void
325 {
326 m_logical_loc = logical_loc;
327 }
328
329 void print (graphviz_out &gv) const;
330
331 void
332 dump () const;
333
334 std::unique_ptr<json::object>
335 to_json_sarif_node () const;
336
337 std::unique_ptr<node>
339 std::map<node *, node *> &node_mapping) const;
340
341private:
342 std::string m_id;
343 std::unique_ptr<std::string> m_label;
344 std::vector<std::unique_ptr<node>> m_children;
345 location_t m_physical_loc;
347};
348
349// An edge in a directed graph, corresponding to SARIF v2.1.0 section 3.41.
350
351class edge : public object
352{
353 public:
354 virtual ~edge () {}
355
356 /* SARIF requires us to provide unique edge IDs within a graph,
357 but otherwise we don't need them.
358 Pass in nullptr for the id to get the graph to generate a unique
359 edge id for us. */
361 const char *id,
362 node &src_node,
363 node &dst_node)
364 : m_id (g.make_edge_id (id)),
365 m_src_node (src_node),
366 m_dst_node (dst_node)
367 {
368 g.add_edge_id (m_id, *this);
369 }
370
371 std::string
372 get_id () const { return m_id; }
373
374 const char *
375 get_label () const
376 {
377 if (!m_label)
378 return nullptr;
379 return m_label->c_str ();
380 }
381
382 void
383 set_label (const char *label)
384 {
385 if (label)
386 m_label = std::make_unique<std::string> (label);
387 else
388 m_label = nullptr;
389 }
390
391 node &
392 get_src_node () const { return m_src_node; }
393
394 node &
395 get_dst_node () const { return m_dst_node; }
396
397 void
398 dump () const;
399
400 std::unique_ptr<json::object>
401 to_json_sarif_edge () const;
402
403 std::unique_ptr<edge>
405 const std::map<diagnostics::digraphs::node *, diagnostics::digraphs::node *> &node_mapping) const;
406
407private:
408 std::string m_id;
409 std::unique_ptr<std::string> m_label;
412};
413
414} // namespace digraphs
415} // namespace diagnostics
416
417#endif /* ! GCC_DIAGNOSTICS_DIGRAPHS_H */
Definition diagnostics/digraphs.h:123
std::unique_ptr< std::string > m_description
Definition diagnostics/digraphs.h:244
digraph()
Definition diagnostics/digraphs.h:128
void set_graph_kind(const char *)
Definition diagnostics/digraphs.cc:375
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:369
std::vector< std::unique_ptr< edge > > m_edges
Definition diagnostics/digraphs.h:248
size_t m_next_edge_id_index
Definition diagnostics/digraphs.h:249
std::unique_ptr< digraph > clone() const
Definition diagnostics/digraphs.cc:307
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:231
std::unique_ptr< json::object > make_json_sarif_graph() const
Definition diagnostics/digraphs.cc:294
std::unique_ptr< dot::graph > make_dot_graph() const
Definition diagnostics/digraphs.cc:300
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:288
void add_edge_id(std::string edge_id, edge &new_edge)
Definition diagnostics/digraphs.h:236
std::map< std::string, node * > m_id_to_node_map
Definition diagnostics/digraphs.h:245
std::string make_edge_id(const char *edge_id)
Definition diagnostics/digraphs.cc:347
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:247
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:246
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:352
edge(digraph &g, const char *id, node &src_node, node &dst_node)
Definition diagnostics/digraphs.h:360
std::string get_id() const
Definition diagnostics/digraphs.h:372
node & m_src_node
Definition diagnostics/digraphs.h:410
virtual ~edge()
Definition diagnostics/digraphs.h:354
std::string m_id
Definition diagnostics/digraphs.h:408
void dump() const
Definition diagnostics/digraphs.cc:435
node & get_dst_node() const
Definition diagnostics/digraphs.h:395
node & m_dst_node
Definition diagnostics/digraphs.h:411
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:441
std::unique_ptr< std::string > m_label
Definition diagnostics/digraphs.h:409
void set_label(const char *label)
Definition diagnostics/digraphs.h:383
const char * get_label() const
Definition diagnostics/digraphs.h:375
node & get_src_node() const
Definition diagnostics/digraphs.h:392
Definition diagnostics/digraphs.h:255
std::string get_id() const
Definition diagnostics/digraphs.h:268
std::unique_ptr< json::object > to_json_sarif_node() const
Definition diagnostics/digraphs.cc:389
void add_child(std::unique_ptr< node > child)
Definition diagnostics/digraphs.h:299
void dump() const
Definition diagnostics/digraphs.cc:383
std::unique_ptr< node > clone(digraph &new_graph, std::map< node *, node * > &node_mapping) const
Definition diagnostics/digraphs.cc:395
void set_label(std::string label)
Definition diagnostics/digraphs.h:287
std::unique_ptr< std::string > m_label
Definition diagnostics/digraphs.h:343
node(const node &)=delete
std::vector< std::unique_ptr< node > > m_children
Definition diagnostics/digraphs.h:344
location_t get_physical_loc() const
Definition diagnostics/digraphs.h:306
logical_locations::key get_logical_loc() const
Definition diagnostics/digraphs.h:318
std::string m_id
Definition diagnostics/digraphs.h:342
void set_physical_loc(location_t physical_loc)
Definition diagnostics/digraphs.h:312
void set_label(const char *label)
Definition diagnostics/digraphs.h:279
size_t get_num_children() const
Definition diagnostics/digraphs.h:293
void print(graphviz_out &gv) const
const char * get_label() const
Definition diagnostics/digraphs.h:271
node(digraph &g, std::string id)
Definition diagnostics/digraphs.h:259
virtual ~node()
Definition diagnostics/digraphs.h:257
node & get_child(size_t idx) const
Definition diagnostics/digraphs.h:296
location_t m_physical_loc
Definition diagnostics/digraphs.h:345
logical_locations::key m_logical_loc
Definition diagnostics/digraphs.h:346
void set_logical_loc(logical_locations::key logical_loc)
Definition diagnostics/digraphs.h:324
Definition diagnostics/digraphs.h:57
tristate get_property_as_tristate(const json::bool_property &property) const
Definition diagnostics/digraphs.cc:231
const char * get_property(const json::string_property &property) const
Definition diagnostics/digraphs.cc:179
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:200
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:278
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:190
Definition logical-locations.h:101
Definition graphviz.h:385
Definition json.h:257
Definition json.h:188
Definition json.h:159
Definition tristate.h:26
gcc::context * g
Definition context.cc:29
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 coretypes.h:167
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:814