CBMC
class_hierarchy.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Class Hierarchy
4 
5 Author: Daniel Kroening
6 
7 Date: April 2016
8 
9 \*******************************************************************/
10 
13 
14 #include "class_hierarchy.h"
15 
16 #include <util/json_stream.h>
17 #include <util/std_types.h>
18 #include <util/symbol_table_base.h>
19 #include <util/ui_message.h>
20 
21 #include <iterator>
22 #include <ostream>
23 
30 {
31  // Add nodes for all classes:
32  for(const auto &symbol_pair : symbol_table.symbols)
33  {
34  if(symbol_pair.second.is_type && symbol_pair.second.type.id() == ID_struct)
35  {
36  node_indext new_node_index = add_node();
37  nodes_by_name[symbol_pair.first] = new_node_index;
38  (*this)[new_node_index].class_identifier = symbol_pair.first;
39  }
40  }
41 
42  // Add parent -> child edges:
43  for(const auto &symbol_pair : symbol_table.symbols)
44  {
45  if(symbol_pair.second.is_type && symbol_pair.second.type.id() == ID_struct)
46  {
47  const struct_typet &struct_type = to_struct_type(symbol_pair.second.type);
48 
49  for(const auto &base : struct_type.bases())
50  {
51  const irep_idt &parent = base.type().get_identifier();
52  if(!parent.empty())
53  {
54  const auto parent_node_it = nodes_by_name.find(parent);
56  parent_node_it != nodes_by_name.end(),
57  "parent class not in symbol table");
58  add_edge(parent_node_it->second, nodes_by_name.at(symbol_pair.first));
59  }
60  }
61  }
62  }
63 }
64 
68  const std::vector<node_indext> &node_indices) const
69 {
70  idst result;
72  node_indices.begin(),
73  node_indices.end(),
74  back_inserter(result),
75  [&](const node_indext &node_index) {
76  return (*this)[node_index].class_identifier;
77  });
78  return result;
79 }
80 
86 {
87  const node_indext &node_index = nodes_by_name.at(c);
88  const auto &child_indices = get_successors(node_index);
89  return ids_from_indices(child_indices);
90 }
91 
94  const irep_idt &c,
95  bool forwards) const
96 {
97  idst direct_child_ids;
98  const node_indext &node_index = nodes_by_name.at(c);
99  const auto &reachable_indices = get_reachable(node_index, forwards);
100  auto reachable_ids = ids_from_indices(reachable_indices);
101  // Remove c itself from the list
102  // TODO Adding it first and then removing it is not ideal. It would be
103  // better to define a function grapht::get_other_reachable and directly use
104  // that here.
105  reachable_ids.erase(
106  std::remove(reachable_ids.begin(), reachable_ids.end(), c),
107  reachable_ids.end());
108  return reachable_ids;
109 }
110 
116 {
117  return get_other_reachable_ids(c, true);
118 }
119 
125 {
126  return get_other_reachable_ids(c, false);
127 }
128 
130  const irep_idt &c,
131  idst &dest) const
132 {
133  class_mapt::const_iterator it=class_map.find(c);
134  if(it==class_map.end())
135  return;
136  const entryt &entry=it->second;
137 
138  for(const auto &child : entry.children)
139  dest.push_back(child);
140 
141  // recursive calls
142  for(const auto &child : entry.children)
143  get_children_trans_rec(child, dest);
144 }
145 
151 {
152  for(const auto &symbol_pair : symbol_table.symbols)
153  {
154  if(symbol_pair.second.is_type && symbol_pair.second.type.id() == ID_struct)
155  {
156  const struct_typet &struct_type = to_struct_type(symbol_pair.second.type);
157 
158  class_map[symbol_pair.first].is_abstract =
159  struct_type.get_bool(ID_abstract);
160 
161  for(const auto &base : struct_type.bases())
162  {
163  const irep_idt &parent = base.type().get_identifier();
164  if(parent.empty())
165  continue;
166 
167  class_map[parent].children.push_back(symbol_pair.first);
168  class_map[symbol_pair.first].parents.push_back(parent);
169  }
170  }
171  }
172 }
173 
180  const irep_idt &c,
181  idst &dest) const
182 {
183  class_mapt::const_iterator it=class_map.find(c);
184  if(it==class_map.end())
185  return;
186  const entryt &entry=it->second;
187 
188  for(const auto &child : entry.parents)
189  dest.push_back(child);
190 
191  // recursive calls
192  for(const auto &child : entry.parents)
193  get_parents_trans_rec(child, dest);
194 }
195 
199 void class_hierarchyt::output(std::ostream &out, bool children_only) const
200 {
201  for(const auto &c : class_map)
202  {
203  out << c.first << (c.second.is_abstract ? " (abstract)" : "") << ":\n";
204  if(!children_only)
205  {
206  out << " parents:\n";
207  for(const auto &pa : c.second.parents)
208  out << " " << pa << '\n';
209  }
210  out << " children:\n";
211  for(const auto &ch : c.second.children)
212  out << " " << ch << '\n';
213  }
214 }
215 
218 void class_hierarchyt::output_dot(std::ostream &ostr) const
219 {
220  ostr << "digraph class_hierarchy {\n"
221  << " rankdir=BT;\n"
222  << " node [fontsize=12 shape=box];\n";
223  for(const auto &c : class_map)
224  {
225  for(const auto &ch : c.second.parents)
226  {
227  ostr << " \"" << c.first << "\" -> "
228  << "\"" << ch << "\" "
229  << " [arrowhead=\"vee\"];"
230  << "\n";
231  }
232  }
233  ostr << "}\n";
234 }
235 
240  json_stream_arrayt &json_stream,
241  bool children_only) const
242 {
243  for(const auto &c : class_map)
244  {
245  json_stream_objectt &json_class = json_stream.push_back_stream_object();
246  json_class["name"] = json_stringt(c.first);
247  json_class["isAbstract"] = jsont::json_boolean(c.second.is_abstract);
248  if(!children_only)
249  {
250  json_stream_arrayt &json_parents =
251  json_class.push_back_stream_array("parents");
252  for(const auto &pa : c.second.parents)
253  json_parents.push_back(json_stringt(pa));
254  }
255  json_stream_arrayt &json_children =
256  json_class.push_back_stream_array("children");
257  for(const auto &ch : c.second.children)
258  json_children.push_back(json_stringt(ch));
259  }
260 }
261 
263  const class_hierarchyt &hierarchy,
264  ui_message_handlert &message_handler,
265  bool children_only)
266 {
267  messaget msg(message_handler);
268  switch(message_handler.get_ui())
269  {
271  hierarchy.output(msg.result(), children_only);
272  msg.result() << messaget::eom;
273  break;
275  if(msg.result().tellp() > 0)
276  msg.result() << messaget::eom; // force end of previous message
277  hierarchy.output(message_handler.get_json_stream(), children_only);
278  break;
281  }
282 }
static abstract_object_pointert transform(const exprt &expr, const std::vector< abstract_object_pointert > &operands, const abstract_environmentt &environment, const namespacet &ns)
void show_class_hierarchy(const class_hierarchyt &hierarchy, ui_message_handlert &message_handler, bool children_only)
Output the class hierarchy.
Class Hierarchy.
void populate(const symbol_table_baset &)
Populate the class hierarchy graph, such that there is a node for every struct type in the symbol tab...
nodes_by_namet nodes_by_name
Maps class identifiers onto node indices.
idst get_children_trans(const irep_idt &c) const
Get all the classes that inherit (directly or indirectly) from class c.
std::vector< irep_idt > idst
idst get_direct_children(const irep_idt &c) const
Get all the classes that directly (i.e.
idst get_other_reachable_ids(const irep_idt &c, bool forwards) const
Helper function for get_children_trans and get_parents_trans
idst get_parents_trans(const irep_idt &c) const
Get all the classes that class c inherits from (directly or indirectly).
idst ids_from_indices(const std::vector< node_indext > &nodes) const
Helper function that converts a vector of node_indext to a vector of ids that are stored in the corre...
Non-graph-based representation of the class hierarchy.
void output_dot(std::ostream &) const
Output class hierarchy in Graphviz DOT format.
void get_parents_trans_rec(const irep_idt &, idst &) const
Get all the classes that class c inherits from (directly or indirectly).
class_mapt class_map
void operator()(const symbol_table_baset &)
Looks for all the struct types in the symbol table and construct a map from class names to a data str...
void get_children_trans_rec(const irep_idt &, idst &) const
void output(std::ostream &, bool children_only) const
Output the class hierarchy in plain text.
std::vector< irep_idt > idst
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
bool empty() const
Definition: dstring.h:89
std::vector< node_indext > get_reachable(node_indext src, bool forwards) const
Run depth-first search on the graph, starting from a single source node.
Definition: graph.h:602
node_indext add_node(arguments &&... values)
Definition: graph.h:180
void add_edge(node_indext a, node_indext b)
Definition: graph.h:232
std::vector< node_indext > get_successors(const node_indext &n) const
Definition: graph.h:956
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:57
Provides methods for streaming JSON arrays.
Definition: json_stream.h:93
void push_back(const jsont &json)
Push back a JSON element into the current array stream.
Definition: json_stream.h:106
json_stream_objectt & push_back_stream_object()
Add a JSON object child stream.
Definition: json_stream.cpp:82
Provides methods for streaming JSON objects.
Definition: json_stream.h:140
json_stream_arrayt & push_back_stream_array(const std::string &key)
Add a JSON array stream for a specific key.
static jsont json_boolean(bool value)
Definition: json.h:97
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:154
mstreamt & result() const
Definition: message.h:401
static eomt eom
Definition: message.h:289
Structure type, corresponds to C style structs.
Definition: std_types.h:231
const basest & bases() const
Get the collection of base classes/structs.
Definition: std_types.h:262
The symbol table base class interface.
const symbolst & symbols
Read-only field, used to look up symbols given their names.
virtual uit get_ui() const
Definition: ui_message.h:33
virtual json_stream_arrayt & get_json_stream()
Definition: ui_message.h:40
std::size_t node_indext
Definition: scope_tree.h:19
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:534
#define UNIMPLEMENTED
Definition: invariant.h:558
Pre-defined types.
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
Author: Diffblue Ltd.