GCC Middle and Back End API Reference
diagnostic-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_DIAGNOSTIC_DIGRAPHS_H
22#define GCC_DIAGNOSTIC_DIGRAPHS_H
23
24#include "json.h"
25#include "logical-location.h"
26
27class graphviz_out;
28
29class sarif_graph;
30class sarif_node;
31class sarif_edge;
32
33namespace dot { class graph; }
34
35namespace diagnostics {
36namespace digraphs {
37
38/* A family of classes: digraph, node, and edge, closely related to
39 SARIF's graph, node, and edge types (SARIF v2.1.0 sections 3.39-3.41).
40
41 Nodes can have child nodes, allowing for arbitrarily deep nesting.
42 Edges can be between any pair of nodes (potentially at different
43 nesting levels).
44
45 Digraphs, nodes, and edges also optionally have a JSON property bag,
46 allowing round-tripping of arbitrary key/value pairs through SARIF. */
47
48class digraph;
49class node;
50class edge;
51
52/* A base class for digraph, node, and edge to allow them to have
53 an optional JSON property bag. */
54
55class object
56{
57public:
58 const char *
59 get_attr (const char *key_prefix,
60 const char *key) const;
61
62 void
63 set_attr (const char *key_prefix,
64 const char *key,
65 const char *value);
66
67 void
68 set_json_attr (const char *key_prefix,
69 const char *key,
70 std::unique_ptr<json::value> value);
71
73 get_property_bag () const { return m_property_bag.get (); }
74
75 void
76 set_property_bag (std::unique_ptr<json::object> property_bag)
77 {
78 m_property_bag = std::move (property_bag);
79 }
80
81private:
82 std::unique_ptr<json::object> m_property_bag;
83};
84
85// A directed graph, corresponding to SARIF v2.1.0 section 3.39.
86
87class digraph : public object
88{
89 public:
90 friend class node;
91 friend class edge;
92
94 virtual ~digraph () {}
95
96 const char *
98 {
99 if (!m_description)
100 return nullptr;
101 return m_description->c_str ();
102 }
103
104 void
105 set_description (const char *desc)
106 {
107 if (desc)
108 m_description = std::make_unique<std::string> (desc);
109 else
110 m_description = nullptr;
111 }
112 void
113 set_description (std::string desc)
114 {
115 m_description = std::make_unique<std::string> (std::move (desc));
116 }
117
118 node *
119 get_node_by_id (const char *id) const
120 {
121 auto iter = m_id_to_node_map.find (id);
122 if (iter == m_id_to_node_map.end ())
123 return nullptr;
124 return iter->second;
125 }
126
127 edge *
128 get_edge_by_id (const char *id) const
129 {
130 auto iter = m_id_to_edge_map.find (id);
131 if (iter == m_id_to_edge_map.end ())
132 return nullptr;
133 return iter->second;
134 }
135
136 size_t
138 {
139 return m_nodes.size ();
140 }
141
142 node &
143 get_node (size_t idx) const
144 {
145 return *m_nodes[idx].get ();
146 }
147
148 size_t
150 {
151 return m_edges.size ();
152 }
153
154 edge &
155 get_edge (size_t idx) const
156 {
157 return *m_edges[idx].get ();
158 }
159
160 void
161 dump () const;
162
163 std::unique_ptr<json::object>
164 make_json_sarif_graph () const;
165
166 std::unique_ptr<dot::graph>
167 make_dot_graph () const;
168
169 void
170 add_node (std::unique_ptr<node> n)
171 {
172 gcc_assert (n);
173 m_nodes.push_back (std::move (n));
174 }
175
176 void
177 add_edge (std::unique_ptr<edge> e)
178 {
179 gcc_assert (e);
180 m_edges.push_back (std::move (e));
181 }
182
183 void
184 add_edge (const char *id,
185 node &src_node,
186 node &dst_node,
187 const char *label = nullptr);
188
189 std::unique_ptr<digraph> clone () const;
190
191 private:
192 void
193 add_node_id (std::string node_id, node &new_node)
194 {
195 m_id_to_node_map.insert ({std::move (node_id), &new_node});
196 }
197 void
198 add_edge_id (std::string edge_id, edge &new_edge)
199 {
200 m_id_to_edge_map.insert ({std::move (edge_id), &new_edge});
201 }
202
203 std::string
204 make_edge_id (const char *edge_id);
205
206 std::unique_ptr<std::string> m_description;
207 std::map<std::string, node *> m_id_to_node_map;
208 std::map<std::string, edge *> m_id_to_edge_map;
209 std::vector<std::unique_ptr<node>> m_nodes;
210 std::vector<std::unique_ptr<edge>> m_edges;
212};
213
214// A node in a directed graph, corresponding to SARIF v2.1.0 section 3.40.
215
216class node : public object
217{
218 public:
219 virtual ~node () {}
220
221 node (digraph &g, std::string id)
222 : m_id (id),
224 {
225 g.add_node_id (std::move (id), *this);
226 }
227 node (const node &) = delete;
228
229 std::string
230 get_id () const { return m_id; }
231
232 const char *
233 get_label () const
234 {
235 if (!m_label)
236 return nullptr;
237 return m_label->c_str ();
238 }
239
240 void
241 set_label (const char *label)
242 {
243 if (label)
244 m_label = std::make_unique<std::string> (label);
245 else
246 m_label = nullptr;
247 }
248 void
249 set_label (std::string label)
250 {
251 m_label = std::make_unique<std::string> (std::move (label));
252 }
253
254 size_t
255 get_num_children () const { return m_children.size (); }
256
257 node &
258 get_child (size_t idx) const { return *m_children[idx].get (); }
259
260 void
261 add_child (std::unique_ptr<node> child)
262 {
263 gcc_assert (child);
264 m_children.push_back (std::move (child));
265 }
266
267 location_t
269 {
270 return m_physical_loc;
271 }
272
273 void
274 set_physical_loc (location_t physical_loc)
275 {
276 m_physical_loc = physical_loc;
277 }
278
281 {
282 return m_logical_loc;
283 }
284
285 void
287 {
288 m_logical_loc = logical_loc;
289 }
290
291 void print (graphviz_out &gv) const;
292
293 void
294 dump () const;
295
296 std::unique_ptr<json::object>
297 to_json_sarif_node () const;
298
299 std::unique_ptr<node>
301 std::map<node *, node *> &node_mapping) const;
302
303 private:
304 std::string m_id;
305 std::unique_ptr<std::string> m_label;
306 std::vector<std::unique_ptr<node>> m_children;
307 location_t m_physical_loc;
309};
310
311// An edge in a directed graph, corresponding to SARIF v2.1.0 section 3.41.
312
313class edge : public object
314{
315 public:
316 virtual ~edge () {}
317
318 /* SARIF requires us to provide unique edge IDs within a graph,
319 but otherwise we don't need them.
320 Pass in nullptr for the id to get the graph to generate a unique
321 edge id for us. */
323 const char *id,
324 node &src_node,
325 node &dst_node)
326 : m_id (g.make_edge_id (id)),
327 m_src_node (src_node),
328 m_dst_node (dst_node)
329 {
330 g.add_edge_id (m_id, *this);
331 }
332
333 std::string
334 get_id () const { return m_id; }
335
336 const char *
337 get_label () const
338 {
339 if (!m_label)
340 return nullptr;
341 return m_label->c_str ();
342 }
343
344 void
345 set_label (const char *label)
346 {
347 if (label)
348 m_label = std::make_unique<std::string> (label);
349 else
350 m_label = nullptr;
351 }
352
353 node &
354 get_src_node () const { return m_src_node; }
355
356 node &
357 get_dst_node () const { return m_dst_node; }
358
359 void
360 dump () const;
361
362 std::unique_ptr<json::object>
363 to_json_sarif_edge () const;
364
365 std::unique_ptr<edge>
367 const std::map<diagnostics::digraphs::node *, diagnostics::digraphs::node *> &node_mapping) const;
368
369private:
370 std::string m_id;
371 std::unique_ptr<std::string> m_label;
374};
375
376/* Abstract base class for lazily creating
377 a digraph on demand.
378
379 This allows us to avoid the work of creating the digraph for
380 the common case where we just have a text sink. */
381
383{
384public:
385 virtual ~lazy_digraph () {}
386
387 const digraph &
388 get_or_create_digraph () const;
389
390private:
391 virtual std::unique_ptr<digraph>
392 create_digraph () const = 0;
393
394 mutable std::unique_ptr<digraph> m_digraph;
395};
396
397/* Abstract base class for lazily creating a collection of
398 digraphs on demand.
399
400 This allows us to avoid the work of creating the digraphs for
401 the common case where we just have a text sink. */
402
404{
405public:
406 virtual ~lazy_digraphs () {}
407
408 const std::vector<std::unique_ptr<digraph>> &
409 get_or_create_digraphs () const;
410
411private:
412 virtual std::unique_ptr<std::vector<std::unique_ptr<digraph>>>
413 create_digraphs () const = 0;
414
415 mutable std::unique_ptr<std::vector<std::unique_ptr<digraph>>> m_digraphs;
416};
417
418} // namespace digraphs
419} // namespace diagnostics
420
421#endif /* ! GCC_DIAGNOSTIC_DIGRAPHS_H */
Definition diagnostic-digraphs.h:88
std::unique_ptr< std::string > m_description
Definition diagnostic-digraphs.h:206
digraph()
Definition diagnostic-digraphs.h:93
friend class node
Definition diagnostic-digraphs.h:90
size_t get_num_edges() const
Definition diagnostic-digraphs.h:149
edge * get_edge_by_id(const char *id) const
Definition diagnostic-digraphs.h:128
friend class edge
Definition diagnostic-digraphs.h:91
std::vector< std::unique_ptr< edge > > m_edges
Definition diagnostic-digraphs.h:210
size_t m_next_edge_id_index
Definition diagnostic-digraphs.h:211
void set_description(std::string desc)
Definition diagnostic-digraphs.h:113
void add_node_id(std::string node_id, node &new_node)
Definition diagnostic-digraphs.h:193
std::unique_ptr< json::object > make_json_sarif_graph() const
Definition diagnostic-digraphs.cc:213
std::unique_ptr< dot::graph > make_dot_graph() const
Definition diagnostic-digraphs.cc:219
node * get_node_by_id(const char *id) const
Definition diagnostic-digraphs.h:119
void add_node(std::unique_ptr< node > n)
Definition diagnostic-digraphs.h:170
void dump() const
Definition diagnostic-digraphs.cc:207
void add_edge_id(std::string edge_id, edge &new_edge)
Definition diagnostic-digraphs.h:198
std::map< std::string, node * > m_id_to_node_map
Definition diagnostic-digraphs.h:207
std::string make_edge_id(const char *edge_id)
Definition diagnostic-digraphs.cc:266
const char * get_description() const
Definition diagnostic-digraphs.h:97
std::unique_ptr< digraph > clone() const
Definition diagnostic-digraphs.cc:226
edge & get_edge(size_t idx) const
Definition diagnostic-digraphs.h:155
size_t get_num_nodes() const
Definition diagnostic-digraphs.h:137
virtual ~digraph()
Definition diagnostic-digraphs.h:94
std::vector< std::unique_ptr< node > > m_nodes
Definition diagnostic-digraphs.h:209
void add_edge(std::unique_ptr< edge > e)
Definition diagnostic-digraphs.h:177
std::map< std::string, edge * > m_id_to_edge_map
Definition diagnostic-digraphs.h:208
node & get_node(size_t idx) const
Definition diagnostic-digraphs.h:143
void set_description(const char *desc)
Definition diagnostic-digraphs.h:105
Definition diagnostic-digraphs.h:314
edge(digraph &g, const char *id, node &src_node, node &dst_node)
Definition diagnostic-digraphs.h:322
std::string get_id() const
Definition diagnostic-digraphs.h:334
node & m_src_node
Definition diagnostic-digraphs.h:372
virtual ~edge()
Definition diagnostic-digraphs.h:316
std::string m_id
Definition diagnostic-digraphs.h:370
void dump() const
Definition diagnostic-digraphs.cc:343
node & get_dst_node() const
Definition diagnostic-digraphs.h:357
node & m_dst_node
Definition diagnostic-digraphs.h:373
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 diagnostic-digraphs.cc:349
std::unique_ptr< std::string > m_label
Definition diagnostic-digraphs.h:371
void set_label(const char *label)
Definition diagnostic-digraphs.h:345
const char * get_label() const
Definition diagnostic-digraphs.h:337
node & get_src_node() const
Definition diagnostic-digraphs.h:354
Definition diagnostic-digraphs.h:383
std::unique_ptr< digraph > m_digraph
Definition diagnostic-digraphs.h:394
virtual ~lazy_digraph()
Definition diagnostic-digraphs.h:385
virtual std::unique_ptr< digraph > create_digraph() const =0
const digraph & get_or_create_digraph() const
Definition diagnostic-digraphs.cc:357
Definition diagnostic-digraphs.h:404
const std::vector< std::unique_ptr< digraph > > & get_or_create_digraphs() const
Definition diagnostic-digraphs.cc:368
virtual std::unique_ptr< std::vector< std::unique_ptr< digraph > > > create_digraphs() const =0
virtual ~lazy_digraphs()
Definition diagnostic-digraphs.h:406
std::unique_ptr< std::vector< std::unique_ptr< digraph > > > m_digraphs
Definition diagnostic-digraphs.h:415
Definition diagnostic-digraphs.h:217
std::unique_ptr< json::object > to_json_sarif_node() const
Definition diagnostic-digraphs.cc:296
std::string get_id() const
Definition diagnostic-digraphs.h:230
void set_logical_loc(logical_location logical_loc)
Definition diagnostic-digraphs.h:286
void add_child(std::unique_ptr< node > child)
Definition diagnostic-digraphs.h:261
std::unique_ptr< node > clone(digraph &new_graph, std::map< node *, node * > &node_mapping) const
Definition diagnostic-digraphs.cc:302
void set_label(std::string label)
Definition diagnostic-digraphs.h:249
std::unique_ptr< std::string > m_label
Definition diagnostic-digraphs.h:305
node(const node &)=delete
logical_location m_logical_loc
Definition diagnostic-digraphs.h:308
std::vector< std::unique_ptr< node > > m_children
Definition diagnostic-digraphs.h:306
location_t get_physical_loc() const
Definition diagnostic-digraphs.h:268
void dump() const
Definition diagnostic-digraphs.cc:290
std::string m_id
Definition diagnostic-digraphs.h:304
void set_physical_loc(location_t physical_loc)
Definition diagnostic-digraphs.h:274
void set_label(const char *label)
Definition diagnostic-digraphs.h:241
size_t get_num_children() const
Definition diagnostic-digraphs.h:255
void print(graphviz_out &gv) const
const char * get_label() const
Definition diagnostic-digraphs.h:233
node(digraph &g, std::string id)
Definition diagnostic-digraphs.h:221
virtual ~node()
Definition diagnostic-digraphs.h:219
node & get_child(size_t idx) const
Definition diagnostic-digraphs.h:258
logical_location get_logical_loc() const
Definition diagnostic-digraphs.h:280
location_t m_physical_loc
Definition diagnostic-digraphs.h:307
Definition diagnostic-digraphs.h:56
void set_attr(const char *key_prefix, const char *key, const char *value)
Definition diagnostic-digraphs.cc:189
const char * get_attr(const char *key_prefix, const char *key) const
Definition diagnostic-digraphs.cc:176
void set_property_bag(std::unique_ptr< json::object > property_bag)
Definition diagnostic-digraphs.h:76
json::object * get_property_bag() const
Definition diagnostic-digraphs.h:73
void set_json_attr(const char *key_prefix, const char *key, std::unique_ptr< json::value > value)
Definition diagnostic-digraphs.cc:196
std::unique_ptr< json::object > m_property_bag
Definition diagnostic-digraphs.h:82
Definition graphviz.h:385
Definition json.h:149
Definition diagnostic-format-sarif.h:169
Definition diagnostic-format-sarif.h:155
Definition diagnostic-format-sarif.h:162
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
logical_location_manager::key logical_location
Definition logical-location.h:173
@ value
Definition logical-location.h:59
Definition diagnostic-digraphs.h:36
Definition diagnostic-digraphs.h:35
Definition diagnostic-digraphs.h:33
Definition graphviz.h:160
Definition collect2.cc:168
#define gcc_assert(EXPR)
Definition system.h:814