CBMC
remove_virtual_functions.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Remove Virtual Function (Method) Calls
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
12 
13 #include <util/expr_iterator.h>
14 #include <util/expr_util.h>
15 #include <util/fresh_symbol.h>
16 #include <util/pointer_expr.h>
17 
18 #include "class_hierarchy.h"
19 #include "class_identifier.h"
20 #include "goto_model.h"
21 #include "remove_skip.h"
23 
24 #include <algorithm>
25 
27 {
28 public:
30  const symbol_table_baset &_symbol_table,
31  const class_hierarchyt &_class_hierarchy)
32  : ns(_symbol_table),
33  symbol_table(_symbol_table),
34  class_hierarchy(_class_hierarchy)
35  {
36  }
37 
38  void get_functions(const exprt &, dispatch_table_entriest &) const;
39 
40 private:
41  const namespacet ns;
43 
45 
46  typedef std::function<
47  std::optional<resolve_inherited_componentt::inherited_componentt>(
48  const irep_idt &,
49  const irep_idt &)>
52  const irep_idt &,
53  const std::optional<symbol_exprt> &,
54  const irep_idt &,
57  exprt
58  get_method(const irep_idt &class_id, const irep_idt &component_name) const;
59 };
60 
62 {
63 public:
65  symbol_table_baset &_symbol_table,
66  const class_hierarchyt &_class_hierarchy)
67  : class_hierarchy(_class_hierarchy),
68  symbol_table(_symbol_table),
70  {
71  }
72 
73  void operator()(goto_functionst &functions);
74 
76  const irep_idt &function_id,
77  goto_programt &goto_program);
78 
79 private:
83 
85  const irep_idt &function_id,
86  goto_programt &goto_program,
87  goto_programt::targett target);
88 };
89 
95  code_function_callt &call,
96  const symbol_exprt &function_symbol,
97  const namespacet &ns)
98 {
99  call.function() = function_symbol;
100  // Cast the pointers to the correct type for the new callee:
101  // Note the `this` pointer is expected to change type, but other pointers
102  // could also change due to e.g. using a different alias to refer to the same
103  // type (in Java, for example, we see ArrayList.add(ArrayList::E arg)
104  // overriding Collection.add(Collection::E arg))
105  const auto &callee_parameters =
106  to_code_type(ns.lookup(function_symbol.get_identifier()).type).parameters();
107  auto &call_args = call.arguments();
108 
109  INVARIANT(
110  callee_parameters.size() == call_args.size(),
111  "function overrides must have matching argument counts");
112 
113  for(std::size_t i = 0; i < call_args.size(); ++i)
114  {
115  const typet &need_type = callee_parameters[i].type();
116 
117  if(call_args[i].type() != need_type)
118  {
119  // If this wasn't language agnostic code we'd also like to check
120  // compatibility-- for example, Java overrides may have differing generic
121  // qualifiers, but not different base types.
122  INVARIANT(
123  call_args[i].type().id() == ID_pointer,
124  "where overriding function argument types differ, "
125  "those arguments must be pointer-typed");
126  call_args[i] = typecast_exprt(call_args[i], need_type);
127  }
128  }
129 }
130 
146  const goto_programt &goto_program,
148  const exprt &argument_for_this,
149  const symbol_exprt &temp_var_for_this,
150  const source_locationt &vcall_source_loc)
151 {
152  goto_programt checks_directly_preceding_function_call;
153 
154  while(instr_it != goto_program.instructions.cbegin())
155  {
156  instr_it = std::prev(instr_it);
157 
158  if(instr_it->is_assert())
159  {
160  continue;
161  }
162 
163  if(!instr_it->is_assume())
164  {
165  break;
166  }
167 
168  exprt guard = instr_it->condition();
169 
170  bool changed = false;
171  for(auto expr_it = guard.depth_begin(); expr_it != guard.depth_end();
172  ++expr_it)
173  {
174  if(*expr_it == argument_for_this)
175  {
176  expr_it.mutate() = temp_var_for_this;
177  changed = true;
178  }
179  }
180 
181  if(changed)
182  {
183  checks_directly_preceding_function_call.insert_before(
184  checks_directly_preceding_function_call.instructions.cbegin(),
185  goto_programt::make_assumption(guard, vcall_source_loc));
186  }
187  }
188 
189  return checks_directly_preceding_function_call;
190 }
191 
204  const irep_idt &function_id,
205  const goto_programt &goto_program,
206  const goto_programt::targett target,
207  exprt &argument_for_this,
208  symbol_table_baset &symbol_table,
209  const source_locationt &vcall_source_loc,
210  goto_programt &new_code_for_this_argument)
211 {
212  if(has_subexpr(argument_for_this, ID_dereference))
213  {
214  // Create a temporary for the `this` argument. This is so that
215  // \ref goto_symext::try_filter_value_sets can reduce the value-set for
216  // `this` to those elements with the correct class identifier.
217  symbolt &temp_symbol = get_fresh_aux_symbol(
218  argument_for_this.type(),
219  id2string(function_id),
220  "this_argument",
221  vcall_source_loc,
222  symbol_table.lookup_ref(function_id).mode,
223  symbol_table);
224  const symbol_exprt temp_var_for_this = temp_symbol.symbol_expr();
225 
226  new_code_for_this_argument.add(
227  goto_programt::make_decl(temp_var_for_this, vcall_source_loc));
228  new_code_for_this_argument.add(
230  temp_var_for_this, argument_for_this, vcall_source_loc));
231 
232  goto_programt checks_directly_preceding_function_call =
234  goto_program,
235  target,
236  argument_for_this,
237  temp_var_for_this,
238  vcall_source_loc);
239 
240  new_code_for_this_argument.destructive_append(
241  checks_directly_preceding_function_call);
242 
243  argument_for_this = temp_var_for_this;
244  }
245 }
246 
266  symbol_table_baset &symbol_table,
267  const irep_idt &function_id,
268  goto_programt &goto_program,
269  goto_programt::targett target,
270  const dispatch_table_entriest &functions,
271  virtual_dispatch_fallback_actiont fallback_action)
272 {
273  INVARIANT(
274  target->is_function_call(),
275  "remove_virtual_function must target a FUNCTION_CALL instruction");
276 
277  namespacet ns(symbol_table);
278  goto_programt::targett next_target = std::next(target);
279 
280  if(functions.empty())
281  {
282  target->turn_into_skip();
283  remove_skip(goto_program, target, next_target);
284  return next_target; // give up
285  }
286 
287  // only one option?
288  if(functions.size()==1 &&
290  {
291  if(!functions.front().symbol_expr.has_value())
292  {
293  target->turn_into_skip();
294  remove_skip(goto_program, target, next_target);
295  }
296  else
297  {
298  auto c = code_function_callt(
299  target->call_lhs(), target->call_function(), target->call_arguments());
300  create_static_function_call(c, *functions.front().symbol_expr, ns);
301  target->call_function() = c.function();
302  target->call_arguments() = c.arguments();
303  }
304  return next_target;
305  }
306 
307  const auto &vcall_source_loc = target->source_location();
308 
309  code_function_callt code(
310  target->call_lhs(), target->call_function(), target->call_arguments());
311  goto_programt new_code_for_this_argument;
312 
314  function_id,
315  goto_program,
316  target,
317  code.arguments()[0],
318  symbol_table,
319  vcall_source_loc,
320  new_code_for_this_argument);
321 
322  const exprt &this_expr = code.arguments()[0];
323 
324  // Create a skip as the final target for each branch to jump to at the end
325  goto_programt final_skip;
326 
327  goto_programt::targett t_final =
328  final_skip.add(goto_programt::make_skip(vcall_source_loc));
329 
330  // build the calls and gotos
331 
332  goto_programt new_code_calls;
333  goto_programt new_code_gotos;
334 
335  INVARIANT(
336  this_expr.type().id() == ID_pointer, "this parameter must be a pointer");
337  INVARIANT(
338  to_pointer_type(this_expr.type()).base_type() != empty_typet(),
339  "this parameter must not be a void pointer");
340 
341  // So long as `this` is already not `void*` typed, the second parameter
342  // is ignored:
343  exprt this_class_identifier =
345 
346  // If instructed, add an ASSUME(FALSE) to handle the case where we don't
347  // match any expected type:
349  {
350  new_code_calls.add(
351  goto_programt::make_assumption(false_exprt(), vcall_source_loc));
352  }
353 
354  // get initial identifier for grouping
355  INVARIANT(!functions.empty(), "Function dispatch table cannot be empty.");
356  const auto &last_function_symbol = functions.back().symbol_expr;
357 
358  std::map<irep_idt, goto_programt::targett> calls;
359  // Note backwards iteration, to get the fallback candidate first.
360  for(auto it=functions.crbegin(), itend=functions.crend(); it!=itend; ++it)
361  {
362  const auto &fun=*it;
363  irep_idt id_or_empty = fun.symbol_expr.has_value()
364  ? fun.symbol_expr->get_identifier()
365  : irep_idt();
366  auto insertit = calls.insert({id_or_empty, goto_programt::targett()});
367 
368  // Only create one call sequence per possible target:
369  if(insertit.second)
370  {
371  if(fun.symbol_expr.has_value())
372  {
373  // call function
374  auto new_call = code;
375 
376  create_static_function_call(new_call, *fun.symbol_expr, ns);
377 
378  goto_programt::targett t1 = new_code_calls.add(
379  goto_programt::make_function_call(new_call, vcall_source_loc));
380 
381  insertit.first->second = t1;
382  }
383  else
384  {
385  source_locationt annotated_location = vcall_source_loc;
386  // No definition for this type; shouldn't be possible...
387  annotated_location.set_comment(
388  "cannot find calls for " +
389  id2string(code.function().get(ID_identifier)) + " dispatching " +
390  id2string(fun.class_id));
391  insertit.first->second = new_code_calls.add(
392  goto_programt::make_assertion(false_exprt(), annotated_location));
393  }
394 
395  // goto final
396  new_code_calls.add(
397  goto_programt::make_goto(t_final, true_exprt(), vcall_source_loc));
398  }
399 
400  // Fall through to the default callee if possible:
401  if(
402  fallback_action ==
404  fun.symbol_expr.has_value() == last_function_symbol.has_value() &&
405  (!fun.symbol_expr.has_value() ||
406  *fun.symbol_expr == *last_function_symbol))
407  {
408  // Nothing to do
409  }
410  else
411  {
412  const constant_exprt fun_class_identifier(fun.class_id, string_typet());
413  const equal_exprt class_id_test(
414  fun_class_identifier, this_class_identifier);
415 
416  // If the previous GOTO goes to the same callee, join it
417  // (e.g. turning IF x GOTO y into IF x || z GOTO y)
418  if(
419  it != functions.crbegin() &&
420  std::prev(it)->symbol_expr.has_value() == fun.symbol_expr.has_value() &&
421  (!fun.symbol_expr.has_value() ||
422  *(std::prev(it)->symbol_expr) == *fun.symbol_expr))
423  {
424  INVARIANT(
425  !new_code_gotos.empty(),
426  "a dispatch table entry has been processed already, "
427  "which should have created a GOTO");
428  new_code_gotos.instructions.back().condition_nonconst() = or_exprt(
429  new_code_gotos.instructions.back().condition(), class_id_test);
430  }
431  else
432  {
433  new_code_gotos.add(goto_programt::make_goto(
434  insertit.first->second, class_id_test, vcall_source_loc));
435  }
436  }
437  }
438 
439  goto_programt new_code;
440 
441  // patch them all together
442  new_code.destructive_append(new_code_for_this_argument);
443  new_code.destructive_append(new_code_gotos);
444  new_code.destructive_append(new_code_calls);
445  new_code.destructive_append(final_skip);
446 
447  goto_program.destructive_insert(next_target, new_code);
448 
449  // finally, kill original invocation
450  target->turn_into_skip();
451 
452  // only remove skips within the virtual-function handling block
453  remove_skip(goto_program, target, next_target);
454 
455  return next_target;
456 }
457 
468  const irep_idt &function_id,
469  goto_programt &goto_program,
470  goto_programt::targett target)
471 {
472  const exprt &function = as_const(*target).call_function();
473  INVARIANT(
475  "remove_virtual_function must take a function call instruction whose "
476  "function is a class method descriptor ");
477  INVARIANT(
478  !as_const(*target).call_arguments().empty(),
479  "virtual function calls must have at least a this-argument");
480 
482  dispatch_table_entriest functions;
483  get_callees.get_functions(function, functions);
484 
486  symbol_table,
487  function_id,
488  goto_program,
489  target,
490  functions,
492 }
493 
508  const irep_idt &this_id,
509  const std::optional<symbol_exprt> &last_method_defn,
510  const irep_idt &component_name,
511  dispatch_table_entriest &functions,
512  dispatch_table_entries_mapt &entry_map) const
513 {
514  auto findit=class_hierarchy.class_map.find(this_id);
515  if(findit==class_hierarchy.class_map.end())
516  return;
517 
518  for(const auto &child : findit->second.children)
519  {
520  // Skip if we have already visited this and we found a function call that
521  // did not resolve to non java.lang.Object.
522  auto it = entry_map.find(child);
523  if(
524  it != entry_map.end() &&
525  (!it->second.symbol_expr.has_value() ||
526  !it->second.symbol_expr->get_identifier().starts_with(
527  "java::java.lang.Object")))
528  {
529  continue;
530  }
531  exprt method = get_method(child, component_name);
532  dispatch_table_entryt function(child);
533  if(method.is_not_nil())
534  {
535  function.symbol_expr=to_symbol_expr(method);
536  function.symbol_expr->set(ID_C_class, child);
537  }
538  else
539  {
540  function.symbol_expr=last_method_defn;
541  }
542  if(!function.symbol_expr.has_value())
543  {
544  const auto resolved_call = get_inherited_method_implementation(
545  component_name, child, symbol_table);
546  if(resolved_call)
547  {
548  function.class_id = resolved_call->get_class_identifier();
549  const symbolt &called_symbol = symbol_table.lookup_ref(
550  resolved_call->get_full_component_identifier());
551 
552  function.symbol_expr = called_symbol.symbol_expr();
553  function.symbol_expr->set(
554  ID_C_class, resolved_call->get_class_identifier());
555  }
556  }
557  functions.push_back(function);
558  entry_map.emplace(child, function);
559 
561  child, function.symbol_expr, component_name, functions, entry_map);
562  }
563 }
564 
570  const exprt &function,
571  dispatch_table_entriest &functions) const
572 {
573  // class part of function to call
574  const irep_idt class_id=function.get(ID_C_class);
575  const std::string class_id_string(id2string(class_id));
576  const irep_idt function_name = function.get(ID_component_name);
577  const std::string function_name_string(id2string(function_name));
578  INVARIANT(!class_id.empty(), "All virtual functions must have a class");
579 
580  auto resolved_call =
581  get_inherited_method_implementation(function_name, class_id, symbol_table);
582 
583  // might be an abstract function
584  dispatch_table_entryt root_function(class_id);
585 
586  if(resolved_call)
587  {
588  root_function.class_id = resolved_call->get_class_identifier();
589 
590  const symbolt &called_symbol =
591  symbol_table.lookup_ref(resolved_call->get_full_component_identifier());
592 
593  root_function.symbol_expr=called_symbol.symbol_expr();
594  root_function.symbol_expr->set(
595  ID_C_class, resolved_call->get_class_identifier());
596  }
597 
598  // iterate over all children, transitively
599  dispatch_table_entries_mapt entry_map;
601  class_id, root_function.symbol_expr, function_name, functions, entry_map);
602 
603  if(root_function.symbol_expr.has_value())
604  functions.push_back(root_function);
605 
606  // Sort for the identifier of the function call symbol expression, grouping
607  // together calls to the same function. Keep java.lang.Object entries at the
608  // end for fall through. The reasoning is that this is the case with most
609  // entries in realistic cases.
610  std::sort(
611  functions.begin(),
612  functions.end(),
613  [](const dispatch_table_entryt &a, const dispatch_table_entryt &b) {
614  irep_idt a_id = a.symbol_expr.has_value()
615  ? a.symbol_expr->get_identifier()
616  : irep_idt();
617  irep_idt b_id = b.symbol_expr.has_value()
618  ? b.symbol_expr->get_identifier()
619  : irep_idt();
620 
621  if(a_id.starts_with("java::java.lang.Object"))
622  return false;
623  else if(b_id.starts_with("java::java.lang.Object"))
624  return true;
625  else
626  {
627  int cmp = a_id.compare(b_id);
628  if(cmp == 0)
629  return a.class_id < b.class_id;
630  else
631  return cmp < 0;
632  }
633  });
634 }
635 
642  const irep_idt &class_id,
643  const irep_idt &component_name) const
644 {
645  const irep_idt &id=
647  class_id, component_name);
648 
649  const symbolt *symbol;
650  if(ns.lookup(id, symbol))
651  return nil_exprt();
652 
653  return symbol->symbol_expr();
654 }
655 
660  const irep_idt &function_id,
661  goto_programt &goto_program)
662 {
663  bool did_something=false;
664 
665  for(goto_programt::instructionst::iterator
666  target = goto_program.instructions.begin();
667  target != goto_program.instructions.end();
668  ) // remove_virtual_function returns the next instruction to process
669  {
670  if(target->is_function_call())
671  {
673  as_const(*target).call_function()))
674  {
675  target = remove_virtual_function(function_id, goto_program, target);
676  did_something=true;
677  continue;
678  }
679  }
680 
681  ++target;
682  }
683 
684  if(did_something)
685  goto_program.update();
686 
687  return did_something;
688 }
689 
693 {
694  bool did_something=false;
695 
696  for(goto_functionst::function_mapt::iterator f_it=
697  functions.function_map.begin();
698  f_it!=functions.function_map.end();
699  f_it++)
700  {
701  const irep_idt &function_id = f_it->first;
702  goto_programt &goto_program=f_it->second.body;
703 
704  if(remove_virtual_functions(function_id, goto_program))
705  did_something=true;
706  }
707 
708  if(did_something)
709  functions.compute_location_numbers();
710 }
711 
717  symbol_table_baset &symbol_table,
718  goto_functionst &goto_functions)
719 {
720  class_hierarchyt class_hierarchy;
721  class_hierarchy(symbol_table);
722  remove_virtual_functionst rvf(symbol_table, class_hierarchy);
723  rvf(goto_functions);
724 }
725 
734  symbol_table_baset &symbol_table,
735  goto_functionst &goto_functions,
736  const class_hierarchyt &class_hierarchy)
737 {
738  remove_virtual_functionst rvf(symbol_table, class_hierarchy);
739  rvf(goto_functions);
740 }
741 
745 {
747  goto_model.symbol_table, goto_model.goto_functions);
748 }
749 
756  goto_modelt &goto_model,
757  const class_hierarchyt &class_hierarchy)
758 {
760  goto_model.symbol_table, goto_model.goto_functions, class_hierarchy);
761 }
762 
768 {
769  class_hierarchyt class_hierarchy;
770  class_hierarchy(function.get_symbol_table());
771  remove_virtual_functionst rvf(function.get_symbol_table(), class_hierarchy);
773  function.get_function_id(), function.get_goto_function().body);
774 }
775 
784  goto_model_functiont &function,
785  const class_hierarchyt &class_hierarchy)
786 {
787  remove_virtual_functionst rvf(function.get_symbol_table(), class_hierarchy);
789  function.get_function_id(), function.get_goto_function().body);
790 }
791 
811  symbol_table_baset &symbol_table,
812  const irep_idt &function_id,
813  goto_programt &goto_program,
814  goto_programt::targett instruction,
815  const dispatch_table_entriest &dispatch_table,
816  virtual_dispatch_fallback_actiont fallback_action)
817 {
819  symbol_table,
820  function_id,
821  goto_program,
822  instruction,
823  dispatch_table,
824  fallback_action);
825 
826  goto_program.update();
827 
828  return next;
829 }
830 
832  goto_modelt &goto_model,
833  const irep_idt &function_id,
834  goto_programt &goto_program,
835  goto_programt::targett instruction,
836  const dispatch_table_entriest &dispatch_table,
837  virtual_dispatch_fallback_actiont fallback_action)
838 {
840  goto_model.symbol_table,
841  function_id,
842  goto_program,
843  instruction,
844  dispatch_table,
845  fallback_action);
846 }
847 
849  const exprt &function,
850  const symbol_table_baset &symbol_table,
851  const class_hierarchyt &class_hierarchy,
852  dispatch_table_entriest &overridden_functions)
853 {
854  get_virtual_calleest get_callees(symbol_table, class_hierarchy);
855  get_callees.get_functions(function, overridden_functions);
856 }
const T & as_const(T &value)
Return a reference to the same object but ensures the type is const.
Definition: as_const.h:14
static exprt guard(const exprt::operandst &guards, exprt cond)
std::set< irep_idt > get_callees(const call_grapht::directed_grapht &graph, const irep_idt &function)
Get functions directly callable from a given function.
Class Hierarchy.
exprt get_class_identifier_field(const exprt &this_expr_in, const struct_tag_typet &suggested_type, const namespacet &ns)
Extract class identifier.
Non-graph-based representation of the class hierarchy.
class_mapt class_map
goto_instruction_codet representation of a function call statement.
const parameterst & parameters() const
Definition: std_types.h:699
A constant literal expression.
Definition: std_expr.h:2987
std::optional< symbol_exprt > symbol_expr
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
The empty type.
Definition: std_types.h:51
Equality.
Definition: std_expr.h:1361
Base class for all expressions.
Definition: expr.h:56
depth_iteratort depth_end()
Definition: expr.cpp:249
depth_iteratort depth_begin()
Definition: expr.cpp:247
typet & type()
Return the type of the expression.
Definition: expr.h:84
The Boolean constant false.
Definition: std_expr.h:3064
const symbol_table_baset & symbol_table
void get_child_functions_rec(const irep_idt &, const std::optional< symbol_exprt > &, const irep_idt &, dispatch_table_entriest &, dispatch_table_entries_mapt &) const
Used by get_functions to track the most-derived parent that provides an override of a given function.
get_virtual_calleest(const symbol_table_baset &_symbol_table, const class_hierarchyt &_class_hierarchy)
exprt get_method(const irep_idt &class_id, const irep_idt &component_name) const
Returns symbol pointing to a specified method in a specified class.
void get_functions(const exprt &, dispatch_table_entriest &) const
Used to get dispatch entries to call for the given function.
std::function< std::optional< resolve_inherited_componentt::inherited_componentt > const irep_idt &, const irep_idt &)> function_call_resolvert
const class_hierarchyt & class_hierarchy
A collection of goto functions.
function_mapt function_map
void compute_location_numbers()
Interface providing access to a single function in a GOTO model, plus its associated symbol table.
Definition: goto_model.h:190
symbol_tablet symbol_table
Symbol table.
Definition: goto_model.h:31
goto_functionst goto_functions
GOTO functions.
Definition: goto_model.h:34
A generic container class for the GOTO intermediate representation of one function.
Definition: goto_program.h:73
static instructiont make_assumption(const exprt &g, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:945
instructionst instructions
The list of instructions in the goto program.
Definition: goto_program.h:622
void update()
Update all indices.
void destructive_insert(const_targett target, goto_programt &p)
Inserts the given program p before target.
Definition: goto_program.h:730
instructionst::iterator targett
Definition: goto_program.h:614
instructionst::const_iterator const_targett
Definition: goto_program.h:615
void destructive_append(goto_programt &p)
Appends the given program p to *this. p is destroyed.
Definition: goto_program.h:722
static instructiont make_assignment(const code_assignt &_code, const source_locationt &l=source_locationt::nil())
Create an assignment instruction.
static instructiont make_skip(const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:891
static instructiont make_function_call(const code_function_callt &_code, const source_locationt &l=source_locationt::nil())
Create a function call instruction.
targett add(instructiont &&instruction)
Adds a given instruction at the end.
Definition: goto_program.h:739
static instructiont make_goto(targett _target, const source_locationt &l=source_locationt::nil())
bool empty() const
Is the program empty?
Definition: goto_program.h:799
static instructiont make_decl(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:964
static instructiont make_assertion(const exprt &g, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:933
targett insert_before(const_targett target)
Insertion before the instruction pointed-to by the given instruction iterator target.
Definition: goto_program.h:692
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:408
bool is_not_nil() const
Definition: irep.h:368
const irep_idt & id() const
Definition: irep.h:384
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:148
The NIL expression.
Definition: std_expr.h:3073
Boolean OR.
Definition: std_expr.h:2228
const typet & base_type() const
The type of the data what we point to.
Definition: pointer_expr.h:35
remove_virtual_functionst(symbol_table_baset &_symbol_table, const class_hierarchyt &_class_hierarchy)
bool remove_virtual_functions(const irep_idt &function_id, goto_programt &goto_program)
Remove all virtual function calls in a GOTO program and replace them with calls to their most derived...
void operator()(goto_functionst &functions)
Remove virtual function calls from all functions in the specified list and replace them with their mo...
goto_programt::targett remove_virtual_function(const irep_idt &function_id, goto_programt &goto_program, goto_programt::targett target)
Replace specified virtual function call with a static call to its most derived implementation.
const class_hierarchyt & class_hierarchy
static irep_idt build_full_component_identifier(const irep_idt &class_name, const irep_idt &component_name)
Build a component name as found in a GOTO symbol table equivalent to the name of a concrete component...
void set_comment(const irep_idt &comment)
String type.
Definition: std_types.h:957
A struct tag type, i.e., struct_typet with an identifier.
Definition: std_types.h:493
Expression to hold a symbol (variable)
Definition: std_expr.h:131
const irep_idt & get_identifier() const
Definition: std_expr.h:160
The symbol table base class interface.
const symbolt & lookup_ref(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
Symbol table entry.
Definition: symbol.h:28
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition: symbol.cpp:121
irep_idt mode
Language mode.
Definition: symbol.h:49
The Boolean constant true.
Definition: std_expr.h:3055
Semantic type conversion.
Definition: std_expr.h:2068
The type of an expression, extends irept.
Definition: type.h:29
Forward depth-first search iterators These iterators' copy operations are expensive,...
bool has_subexpr(const exprt &expr, const std::function< bool(const exprt &)> &pred)
returns true if the expression has a subexpression that satisfies pred
Definition: expr_util.cpp:141
Deprecated expression utility functions.
symbolt & get_fresh_aux_symbol(const typet &type, const std::string &name_prefix, const std::string &basename_prefix, const source_locationt &source_location, const irep_idt &symbol_mode, const namespacet &ns, symbol_table_baset &symbol_table)
Installs a fresh-named symbol with respect to the given namespace ns with the requested name pattern ...
Fresh auxiliary symbol creation.
Symbol Table + CFG.
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
API to expression classes for Pointers.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
void remove_skip(goto_programt &goto_program, goto_programt::targett begin, goto_programt::targett end)
remove unnecessary skip statements
Definition: remove_skip.cpp:87
Program Transformation.
static void process_this_argument(const irep_idt &function_id, const goto_programt &goto_program, const goto_programt::targett target, exprt &argument_for_this, symbol_table_baset &symbol_table, const source_locationt &vcall_source_loc, goto_programt &new_code_for_this_argument)
If argument_for_this contains a dereference then create a temporary variable for it and use that inst...
static goto_programt::targett replace_virtual_function_with_dispatch_table(symbol_table_baset &symbol_table, const irep_idt &function_id, goto_programt &goto_program, goto_programt::targett target, const dispatch_table_entriest &functions, virtual_dispatch_fallback_actiont fallback_action)
Replace virtual function call with a static function call Achieved by substituting a virtual function...
static goto_programt analyse_checks_directly_preceding_function_call(const goto_programt &goto_program, goto_programt::const_targett instr_it, const exprt &argument_for_this, const symbol_exprt &temp_var_for_this, const source_locationt &vcall_source_loc)
Duplicate ASSUME instructions involving argument_for_this for temp_var_for_this.
goto_programt::targett remove_virtual_function(symbol_table_baset &symbol_table, const irep_idt &function_id, goto_programt &goto_program, goto_programt::targett instruction, const dispatch_table_entriest &dispatch_table, virtual_dispatch_fallback_actiont fallback_action)
Replace virtual function call with a static function call Achieved by substituting a virtual function...
static void create_static_function_call(code_function_callt &call, const symbol_exprt &function_symbol, const namespacet &ns)
Create a concrete function call to replace a virtual one.
void collect_virtual_function_callees(const exprt &function, const symbol_table_baset &symbol_table, const class_hierarchyt &class_hierarchy, dispatch_table_entriest &overridden_functions)
Given a function expression representing a virtual method of a class, the function computes all overr...
void remove_virtual_functions(symbol_table_baset &symbol_table, goto_functionst &goto_functions)
Remove virtual function calls from all functions in the specified list and replace them with their mo...
Functions for replacing virtual function call with a static function calls in functions,...
std::map< irep_idt, dispatch_table_entryt > dispatch_table_entries_mapt
virtual_dispatch_fallback_actiont
Specifies remove_virtual_function's behaviour when the actual supplied parameter does not match any o...
@ ASSUME_FALSE
When no callee type matches, ASSUME false, thus preventing any complete trace from using this path.
@ CALL_LAST_FUNCTION
When no callee type matches, call the last passed function, which is expected to be some safe default...
std::vector< dispatch_table_entryt > dispatch_table_entriest
std::optional< resolve_inherited_componentt::inherited_componentt > get_inherited_method_implementation(const irep_idt &call_basename, const irep_idt &classname, const symbol_table_baset &symbol_table)
Given a class and a component, identify the concrete method it is resolved to.
Given a class and a component (either field or method), find the closest parent that defines that com...
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition: invariant.h:423
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
bool can_cast_expr< class_method_descriptor_exprt >(const exprt &base)
Definition: std_expr.h:3593
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:788
dstringt irep_idt