diff --git a/src/goto-programs/Makefile b/src/goto-programs/Makefile index aa788914562..813be9a18b7 100644 --- a/src/goto-programs/Makefile +++ b/src/goto-programs/Makefile @@ -17,7 +17,7 @@ SRC = goto_convert.cpp goto_convert_function_call.cpp \ goto_trace.cpp xml_goto_trace.cpp vcd_goto_trace.cpp \ graphml_witness.cpp remove_virtual_functions.cpp \ class_hierarchy.cpp show_goto_functions.cpp get_goto_model.cpp \ - slice_global_inits.cpp goto_inline_class.cpp + slice_global_inits.cpp goto_inline_class.cpp class_identifier.cpp INCLUDES= -I .. diff --git a/src/goto-programs/class_identifier.cpp b/src/goto-programs/class_identifier.cpp new file mode 100644 index 00000000000..6e814174e51 --- /dev/null +++ b/src/goto-programs/class_identifier.cpp @@ -0,0 +1,89 @@ +/*******************************************************************\ + +Module: Extract class identifier + +Author: Chris Smowton, chris.smowton@diffblue.com + +\*******************************************************************/ + +#include "class_identifier.h" + +#include +#include + +/*******************************************************************\ + +Function: build_class_identifier + + Inputs: Struct expression + + Outputs: Member expression giving the clsid field of the input, + or its parent, grandparent, etc. + + Purpose: + +\*******************************************************************/ + +static exprt build_class_identifier( + const exprt &src, + const namespacet &ns) +{ + // the class identifier is in the root class + exprt e=src; + + while(1) + { + const typet &type=ns.follow(e.type()); + const struct_typet &struct_type=to_struct_type(type); + const struct_typet::componentst &components=struct_type.components(); + assert(!components.empty()); + + const auto &first_member_name=components.front().get_name(); + member_exprt member_expr( + e, + first_member_name, + components.front().type()); + + if(first_member_name=="@class_identifier") + { + // found it + return member_expr; + } + else + { + e.swap(member_expr); + } + } +} + +/*******************************************************************\ + +Function: get_class_identifier_field + + Inputs: Pointer expression of any pointer type, including void*, + and a recommended access type if the pointer is void-typed. + + Outputs: Member expression to access a class identifier, as above. + + Purpose: + +\*******************************************************************/ + +exprt get_class_identifier_field( + const exprt &this_expr_in, + const symbol_typet &suggested_type, + const namespacet &ns) +{ + // Get a pointer from which we can extract a clsid. + // If it's already a pointer to an object of some sort, just use it; + // if it's void* then use the suggested type. + + exprt this_expr=this_expr_in; + assert(this_expr.type().id()==ID_pointer && + "Non-pointer this-arg in remove-virtuals?"); + const auto &points_to=this_expr.type().subtype(); + if(points_to==empty_typet()) + this_expr=typecast_exprt(this_expr, pointer_typet(suggested_type)); + exprt deref=dereference_exprt(this_expr, this_expr.type().subtype()); + return build_class_identifier(deref, ns); +} diff --git a/src/goto-programs/class_identifier.h b/src/goto-programs/class_identifier.h new file mode 100644 index 00000000000..8ae6dc4ce71 --- /dev/null +++ b/src/goto-programs/class_identifier.h @@ -0,0 +1,21 @@ +/*******************************************************************\ + +Module: Extract class identifier + +Author: Chris Smowton, chris.smowton@diffblue.com + +\*******************************************************************/ + +#ifndef CPROVER_GOTO_PROGRAMS_CLASS_IDENTIFIER_H +#define CPROVER_GOTO_PROGRAMS_CLASS_IDENTIFIER_H + +class exprt; +class namespacet; +class symbol_typet; + +exprt get_class_identifier_field( + const exprt &this_expr, + const symbol_typet &suggested_type, + const namespacet &ns); + +#endif diff --git a/src/goto-programs/remove_virtual_functions.cpp b/src/goto-programs/remove_virtual_functions.cpp index 4da7d62631b..56c89dac3f0 100644 --- a/src/goto-programs/remove_virtual_functions.cpp +++ b/src/goto-programs/remove_virtual_functions.cpp @@ -10,6 +10,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include "class_hierarchy.h" +#include "class_identifier.h" #include "remove_virtual_functions.h" /*******************************************************************\ @@ -61,8 +62,6 @@ class remove_virtual_functionst exprt get_method( const irep_idt &class_id, const irep_idt &component_name) const; - - exprt build_class_identifier(const exprt &); }; /*******************************************************************\ @@ -88,48 +87,6 @@ remove_virtual_functionst::remove_virtual_functionst( /*******************************************************************\ -Function: remove_virtual_functionst::build_class_identifier - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -exprt remove_virtual_functionst::build_class_identifier( - const exprt &src) -{ - // the class identifier is in the root class - exprt e=src; - - while(1) - { - const typet &type=ns.follow(e.type()); - assert(type.id()==ID_struct); - - const struct_typet &struct_type=to_struct_type(type); - const struct_typet::componentst &components=struct_type.components(); - assert(!components.empty()); - - member_exprt member_expr( - e, components.front().get_name(), components.front().type()); - - if(components.front().get_name()=="@class_identifier") - { - // found it - return member_expr; - } - else - { - e=member_expr; - } - } -} - -/*******************************************************************\ - Function: remove_virtual_functionst::remove_virtual_function Inputs: @@ -181,22 +138,12 @@ void remove_virtual_functionst::remove_virtual_function( goto_programt new_code_calls; goto_programt new_code_gotos; - // Get a pointer from which we can extract a clsid. - // If it's already a pointer to an object of some sort, just use it; - // if it's void* then use the parent of all possible candidates, - // which by the nature of get_functions happens to be the last candidate. - exprt this_expr=code.arguments()[0]; - assert(this_expr.type().id()==ID_pointer && - "Non-pointer this-arg in remove-virtuals?"); - const auto &points_to=this_expr.type().subtype(); - if(points_to==empty_typet()) - { - symbol_typet symbol_type(functions.back().class_id); - this_expr=typecast_exprt(this_expr, pointer_typet(symbol_type)); - } - exprt deref=dereference_exprt(this_expr, this_expr.type().subtype()); - exprt c_id2=build_class_identifier(deref); + // If necessary, cast to the last candidate function to + // get the object's clsid. By the structure of get_functions, + // this is the parent of all other classes under consideration. + symbol_typet suggested_type(functions.back().class_id); + exprt c_id2=get_class_identifier_field(this_expr, suggested_type, ns); goto_programt::targett last_function; for(const auto &fun : functions) @@ -249,8 +196,10 @@ void remove_virtual_functionst::remove_virtual_function( const irep_idt comment=it->source_location.get_comment(); it->source_location=target->source_location; it->function=target->function; - if(!property_class.empty()) it->source_location.set_property_class(property_class); - if(!comment.empty()) it->source_location.set_comment(comment); + if(!property_class.empty()) + it->source_location.set_property_class(property_class); + if(!comment.empty()) + it->source_location.set_comment(comment); } goto_programt::targett next_target=target; @@ -355,7 +304,8 @@ void remove_virtual_functionst::get_functions( const class_hierarchyt::idst &parents= class_hierarchy.class_map[c].parents; - if(parents.empty()) break; + if(parents.empty()) + break; c=parents.front(); } @@ -433,7 +383,6 @@ bool remove_virtual_functionst::remove_virtual_functions( if(did_something) { - //remove_skip(goto_program); goto_program.update(); }