CBMC
Loading...
Searching...
No Matches
remove_virtual_functions.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Remove Virtual Function (Method) Calls
4
5Author: 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{
28public:
37
38 void get_functions(const exprt &, dispatch_table_entriest &) const;
39
40private:
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
89
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");
127 }
128 }
129}
130
146 const goto_programt &goto_program,
151{
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 {
175 {
176 expr_it.mutate() = temp_var_for_this;
177 changed = true;
178 }
179 }
180
181 if(changed)
182 {
184 checks_directly_preceding_function_call.instructions.cbegin(),
186 }
187 }
188
190}
191
204 const irep_idt &function_id,
205 const goto_programt &goto_program,
206 const goto_programt::targett target,
208 symbol_table_baset &symbol_table,
211{
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.
218 argument_for_this.type(),
219 id2string(function_id),
220 "this_argument",
222 symbol_table.lookup_ref(function_id).mode,
223 symbol_table);
224 const symbol_exprt temp_var_for_this = temp_symbol.symbol_expr();
225
231
234 goto_program,
235 target,
239
240 new_code_for_this_argument.destructive_append(
242
244 }
245}
246
266 symbol_table_baset &symbol_table,
267 const irep_idt &function_id,
268 goto_programt &goto_program,
270 const dispatch_table_entriest &functions,
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
310 target->call_lhs(), target->call_function(), target->call_arguments());
312
314 function_id,
315 goto_program,
316 target,
317 code.arguments()[0],
318 symbol_table,
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
326
329
330 // build the calls and gotos
331
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:
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(
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();
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
380
381 insertit.first->second = t1;
382 }
383 else
384 {
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(
393 }
394
395 // goto final
396 new_code_calls.add(
398 }
399
400 // Fall through to the default callee if possible:
401 if(
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 {
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 {
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
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,
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
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);
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 {
541 }
542 if(!function.symbol_expr.has_value())
543 {
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
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
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(),
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);
772 rvf.remove_virtual_functions(
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);
788 rvf.remove_virtual_functions(
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,
817{
819 symbol_table,
820 function_id,
821 goto_program,
822 instruction,
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,
838{
840 goto_model.symbol_table,
841 function_id,
842 goto_program,
843 instruction,
846}
847
849 const exprt &function,
850 const symbol_table_baset &symbol_table,
851 const class_hierarchyt &class_hierarchy,
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.
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
Non-graph-based representation of the class hierarchy.
goto_instruction_codet representation of a function call statement.
A constant literal expression.
Definition std_expr.h:3117
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:1366
Base class for all expressions.
Definition expr.h:56
typet & type()
Return the type of the expression.
Definition expr.h:84
The Boolean constant false.
Definition std_expr.h:3199
const symbol_table_baset & symbol_table
std::function< std::optional< resolve_inherited_componentt::inherited_componentt >(const irep_idt &, const irep_idt &)> function_call_resolvert
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.
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
const irep_idt & get_function_id()
Get function id.
Definition goto_model.h:239
goto_functionst::goto_functiont & get_goto_function()
Get GOTO function.
Definition goto_model.h:232
journalling_symbol_tablet & get_symbol_table()
Get symbol table.
Definition goto_model.h:225
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.
static instructiont make_assumption(const exprt &g, const source_locationt &l=source_locationt::nil())
instructionst instructions
The list of instructions in the goto program.
void update()
Update all indices.
void destructive_insert(const_targett target, goto_programt &p)
Inserts the given program p before target.
instructionst::iterator targett
instructionst::const_iterator const_targett
void destructive_append(goto_programt &p)
Appends the given program p to *this. p is destroyed.
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())
static instructiont make_function_call(const code_function_callt &_code, const source_locationt &l=source_locationt::nil())
Create a function call instruction.
static instructiont make_goto(targett _target, const source_locationt &l=source_locationt::nil())
static instructiont make_decl(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
static instructiont make_assertion(const exprt &g, const source_locationt &l=source_locationt::nil())
const irep_idt & get(const irep_idt &name) const
Definition irep.cpp:44
bool is_not_nil() const
Definition irep.h:372
const irep_idt & id() const
Definition irep.h:388
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
The NIL expression.
Definition std_expr.h:3208
Boolean OR.
Definition std_expr.h:2270
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...
String type.
Definition std_types.h:966
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
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
The Boolean constant true.
Definition std_expr.h:3190
Semantic type conversion.
Definition std_expr.h:2073
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
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:44
API to expression classes for Pointers.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
void remove_skip(goto_programt &goto_program, goto_programt::targett begin, goto_programt::targett end)
remove unnecessary skip statements
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
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition std_types.h:788
dstringt irep_idt