|
| 1 | +// Copyright 2016-2017 DiffBlue Limited. All Rights Reserved. |
| 2 | + |
| 3 | +/// \file |
| 4 | +/// Java Bytecode Language Conversion |
| 5 | + |
| 6 | +#include "get_concrete_class_at_random.h" |
| 7 | + |
| 8 | +#include <algorithm> |
| 9 | +#include <random> |
| 10 | + |
| 11 | +#include <util/namespace.h> |
| 12 | +#include <util/std_types.h> |
| 13 | +#include <util/symbol_table.h> |
| 14 | + |
| 15 | +#include <goto-programs/class_hierarchy.h> |
| 16 | + |
| 17 | +/// Get type the pointer is pointing to, replacing it with a concrete |
| 18 | +/// implementation when it is abstract. |
| 19 | +/// \param `pointer_type`: The type of the pointer |
| 20 | +/// \return The subtype of the pointer. If this is an abstract class then we |
| 21 | +/// will randomly select a concrete child class. |
| 22 | +typet get_concrete_class_at_randomt::operator()( |
| 23 | + const pointer_typet &pointer_type) |
| 24 | +{ |
| 25 | + const typet &subtype=ns.follow(pointer_type.subtype()); |
| 26 | + if(subtype.id()==ID_struct) |
| 27 | + { |
| 28 | + const class_typet &class_type=to_class_type(subtype); |
| 29 | + |
| 30 | + if(class_type.is_class() && class_type.is_abstract()) |
| 31 | + { |
| 32 | + return select_concrete_type(class_type); |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + // Here we must return the original subtype as if it is a pointer to a java |
| 37 | + // array java_object_factoryt::gen_nondet_array_init relies on the subtype |
| 38 | + // being a ID_symbol, here we have followed the symbol to its resolution. |
| 39 | + // Perhaps java_object_factoryt::gen_nondet_array_init should support this |
| 40 | + // Perhaps select_concrete_type when it fails should also ensure it doesn't |
| 41 | + // modify the subtype (currently if no concrete implementations we'd do the same |
| 42 | + // - swap a symbol to a struct |
| 43 | + return pointer_type.subtype(); |
| 44 | +} |
| 45 | + |
| 46 | +/// Randomly select a concrete sub-class of an abstract class or interface This |
| 47 | +/// can be then used when analyzing the function. |
| 48 | +/// \param `abstract_type`: an class type that is abstract (i.e. either an |
| 49 | +/// interface or a abstract class). |
| 50 | +/// \return A class_typet that the GOTO code should instantiate to fill this |
| 51 | +/// type. This will be a concrete type unless no concrete types are found that |
| 52 | +/// inherit from the abstract_type. ` |
| 53 | +class_typet get_concrete_class_at_randomt::select_concrete_type( |
| 54 | + const class_typet &abstract_type) |
| 55 | +{ |
| 56 | + if(!abstract_type.is_abstract()) |
| 57 | + throw std::invalid_argument("abstract_type"); |
| 58 | + |
| 59 | + const symbol_tablet &symbol_table=ns.get_symbol_table(); |
| 60 | + // abstract class - we should find a derived class ideally to test with |
| 61 | + class_hierarchyt class_hierachy; |
| 62 | + class_hierachy(symbol_table); |
| 63 | + class_hierarchyt::idst child_ids= |
| 64 | + class_hierachy.get_children_trans(abstract_type.get_string(ID_name)); |
| 65 | + |
| 66 | + // filter out abstract classes |
| 67 | + class_hierarchyt::idst concrete_childen; |
| 68 | + std::copy_if( |
| 69 | + child_ids.begin(), |
| 70 | + child_ids.end(), |
| 71 | + std::back_inserter(concrete_childen), |
| 72 | + [&] (const irep_idt &child_class_id) |
| 73 | + { |
| 74 | + const symbolt &type_symbol=symbol_table.lookup(child_class_id); |
| 75 | + const class_typet &child_type=to_class_type(type_symbol.type); |
| 76 | + return child_type.is_class() && !child_type.is_abstract(); |
| 77 | + }); |
| 78 | + |
| 79 | + |
| 80 | + if(concrete_childen.size()>0) |
| 81 | + { |
| 82 | + //Will be used to obtain a seed for the random number engine |
| 83 | + std::random_device rd; |
| 84 | + //Standard mersenne_twister_engine seeded with rd() |
| 85 | + std::mt19937 gen(rd()); |
| 86 | + std::uniform_int_distribution<unsigned long> class_selector( |
| 87 | + 0, concrete_childen.size()-1); |
| 88 | + unsigned long selected_class_index=class_selector(gen); |
| 89 | + const symbolt &type_symbol= |
| 90 | + symbol_table.lookup(concrete_childen[selected_class_index]); |
| 91 | + const class_typet &child_type=to_class_type(type_symbol.type); |
| 92 | + return child_type; |
| 93 | + } |
| 94 | + else |
| 95 | + { |
| 96 | + // else no children in the symbol table - here the best we can do is |
| 97 | + // mock the interface/abstract object |
| 98 | + return abstract_type; |
| 99 | + } |
| 100 | +} |
0 commit comments