Skip to content

Commit fbf58f1

Browse files
smowtonthk123
authored andcommitted
Remove virtual functions: cast argument types as necessary
For example, when List<E> extends the Collection<E> interface, its overrides of methods accepting an element, such as add(E), are given in terms of its own E, not that of Collection. Therefore we must cast from Collection::E* to List::E* when using that particular override. Only typecast if the parameter types are distinct
1 parent 17f6dbb commit fbf58f1

File tree

1 file changed

+28
-9
lines changed

1 file changed

+28
-9
lines changed

src/goto-programs/remove_virtual_functions.cpp

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,16 +114,35 @@ static void create_static_function_call(
114114
const namespacet &ns)
115115
{
116116
call.function() = function_symbol;
117-
// Cast the `this` pointer to the correct type for the new callee:
118-
const auto &callee_type =
119-
to_code_type(ns.lookup(function_symbol.get_identifier()).type);
120-
const code_typet::parametert *this_param = callee_type.get_this();
117+
// Cast the pointers to the correct type for the new callee:
118+
// Note the `this` pointer is expected to change type, but other pointers
119+
// could also change due to e.g. using a different alias to refer to the same
120+
// type (in Java, for example, we see ArrayList.add(ArrayList::E arg)
121+
// overriding Collection.add(Collection::E arg))
122+
const auto &callee_parameters =
123+
to_code_type(ns.lookup(function_symbol.get_identifier()).type).parameters();
124+
auto &call_args = call.arguments();
125+
121126
INVARIANT(
122-
this_param != nullptr,
123-
"Virtual function callees must have a `this` argument");
124-
typet need_type = this_param->type();
125-
if(!type_eq(call.arguments()[0].type(), need_type, ns))
126-
call.arguments()[0].make_typecast(need_type);
127+
callee_parameters.size() == call_args.size(),
128+
"function overrides must have matching argument counts");
129+
130+
for(std::size_t i = 0; i < call_args.size(); ++i)
131+
{
132+
const typet &need_type = callee_parameters[i].type();
133+
134+
if(!type_eq(call_args[i].type(), need_type, ns))
135+
{
136+
// If this wasn't language agnostic code we'd also like to check
137+
// compatibility-- for example, Java overrides may have differing generic
138+
// qualifiers, but not different base types.
139+
INVARIANT(
140+
call_args[i].type().id() == ID_pointer,
141+
"where overriding function argument types differ, "
142+
"those arguments must be pointer-typed");
143+
call_args[i].make_typecast(need_type);
144+
}
145+
}
127146
}
128147

129148
/// Replace virtual function call with a static function call

0 commit comments

Comments
 (0)