Skip to content

[TG-2842] Specialization for mocked and unsupported generics #1955

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 23, 2018
Merged
41 changes: 28 additions & 13 deletions src/java_bytecode/generic_parameter_specialization_map_keys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,21 @@ const void generic_parameter_specialization_map_keyst::insert_pairs_for_pointer(
pointer_type.subtype().get(ID_identifier) ==
pointer_subtype_struct.get(ID_name));

const java_generic_typet &generic_pointer =
to_java_generic_type(pointer_type);

// If the pointer points to an incomplete class, don't treat the generics
if(!pointer_subtype_struct.get_bool(ID_incomplete_class))
// If the pointer points to:
// - an incomplete class or
// - a class that is neither generic nor implicitly generic (this
// may be due to unsupported class signature)
// then ignore the generic types in the pointer and do not add any pairs.
// TODO TG-1996 should decide how mocking and generics should work
// together. Currently an incomplete class is never marked as generic. If
// this changes in TG-1996 then the condition below should be updated.
if(
!pointer_subtype_struct.get_bool(ID_incomplete_class) &&
(is_java_generic_class_type(pointer_subtype_struct) ||
is_java_implicitly_generic_class_type(pointer_subtype_struct)))
{
PRECONDITION(
is_java_generic_class_type(pointer_subtype_struct) ||
is_java_implicitly_generic_class_type(pointer_subtype_struct));
const java_generic_typet &generic_pointer =
to_java_generic_type(pointer_type);
const std::vector<java_generic_parametert> &generic_parameters =
get_all_generic_parameters(pointer_subtype_struct);

Expand Down Expand Up @@ -135,14 +141,23 @@ const void generic_parameter_specialization_map_keyst::insert_pairs_for_symbol(
const symbol_typet &symbol_type,
const typet &symbol_struct)
{
if(is_java_generic_symbol_type(symbol_type))
// If the struct is:
// - an incomplete class or
// - a class that is neither generic nor implicitly generic (this
// may be due to unsupported class signature)
// then ignore the generic types in the symbol_type and do not add any pairs.
// TODO TG-1996 should decide how mocking and generics should work
// together. Currently an incomplete class is never marked as generic. If
// this changes in TG-1996 then the condition below should be updated.
if(
is_java_generic_symbol_type(symbol_type) &&
!symbol_struct.get_bool(ID_incomplete_class) &&
(is_java_generic_class_type(symbol_struct) ||
is_java_implicitly_generic_class_type(symbol_struct)))
{
java_generic_symbol_typet generic_symbol =
const java_generic_symbol_typet &generic_symbol =
to_java_generic_symbol_type(symbol_type);

PRECONDITION(
is_java_generic_class_type(symbol_struct) ||
is_java_implicitly_generic_class_type(symbol_struct));
const std::vector<java_generic_parametert> &generic_parameters =
get_all_generic_parameters(symbol_struct);

Expand Down
26 changes: 15 additions & 11 deletions src/java_bytecode/java_bytecode_convert_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,12 @@ void java_bytecode_convert_classt::convert(const classt &c)
}
class_type=generic_class_type;
}
catch(unsupported_java_class_signature_exceptiont)
catch(const unsupported_java_class_signature_exceptiont &e)
{
warning() << "we currently don't support parsing for example double "
"bounded, recursive and wild card generics" << eom;
warning() << "Class: " << c.name
<< "\n could not parse signature: " << c.signature.value()
<< "\n " << e.what() << "\n ignoring that the class is generic"
<< eom;
}
}

Expand Down Expand Up @@ -253,11 +255,12 @@ void java_bytecode_convert_classt::convert(const classt &c)
base, superclass_ref.value(), qualified_classname);
class_type.add_base(generic_base);
}
catch(unsupported_java_class_signature_exceptiont)
catch(const unsupported_java_class_signature_exceptiont &e)
{
debug() << "unsupported generic superclass signature "
<< id2string(*superclass_ref)
<< " falling back on using the descriptor" << eom;
warning() << "Superclass: " << c.extends << " of class: " << c.name
<< "\n could not parse signature: " << superclass_ref.value()
<< "\n " << e.what()
<< "\n ignoring that the superclass is generic" << eom;
class_type.add_base(base);
}
}
Expand Down Expand Up @@ -292,11 +295,12 @@ void java_bytecode_convert_classt::convert(const classt &c)
base, interface_ref.value(), qualified_classname);
class_type.add_base(generic_base);
}
catch(unsupported_java_class_signature_exceptiont)
catch(const unsupported_java_class_signature_exceptiont &e)
{
debug() << "unsupported generic interface signature "
<< id2string(*interface_ref)
<< " falling back on using the descriptor" << eom;
warning() << "Interface: " << interface << " of class: " << c.name
<< "\n could not parse signature: " << interface_ref.value()
<< "\n " << e.what()
<< "\n ignoring that the interface is generic" << eom;
class_type.add_base(base);
}
}
Expand Down
21 changes: 12 additions & 9 deletions src/java_bytecode/java_bytecode_convert_method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,18 +286,21 @@ code_typet member_type_lazy(
}
else
{
message.warning() << "method: " << class_name << "." << method_name
<< "\n signature: " << signature.value() << "\n descriptor: "
<< descriptor << "\n different number of parameters, reverting to "
"descriptor" << message.eom;
message.warning() << "Method: " << class_name << "." << method_name
<< "\n signature: " << signature.value()
<< "\n descriptor: " << descriptor
<< "\n different number of parameters, reverting to "
"descriptor"
<< message.eom;
}
}
catch(unsupported_java_class_signature_exceptiont &e)
catch(const unsupported_java_class_signature_exceptiont &e)
{
message.warning() << "method: " << class_name << "." << method_name
<< "\n could not parse signature: " << signature.value() << "\n "
<< e.what() << "\n" << " reverting to descriptor: "
<< descriptor << message.eom;
message.warning() << "Method: " << class_name << "." << method_name
<< "\n could not parse signature: " << signature.value()
<< "\n " << e.what() << "\n"
<< " reverting to descriptor: " << descriptor
<< message.eom;
}
}
return to_code_type(member_type_from_descriptor);
Expand Down
42 changes: 18 additions & 24 deletions unit/goto-programs/goto_program_generics/GenericBases.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,3 @@
// Helper classes
class Wrapper<T> {
public T field;
}

class IntWrapper {
public int i;
}

class TwoWrapper<K, V> {
public K first;
public V second;
}

interface InterfaceWrapper<T> {
public T method(T t);
}

// A class extending a generic class instantiated with a standard library class
class SuperclassInst extends Wrapper<Integer> {
public void foo() {
Expand All @@ -24,14 +6,14 @@ public void foo() {
}

// A class extending a generic class instantiated with a user-defined class
class SuperclassInst2 extends Wrapper<IntWrapper> {
class SuperclassInst2 extends Wrapper<IWrapper> {
public void foo() {
this.field.i = 5;
}
}

// A class extending an instantiated nested generic class
class SuperclassInst3 extends Wrapper<Wrapper<IntWrapper>> {
class SuperclassInst3 extends Wrapper<Wrapper<IWrapper>> {
public void foo() {
this.field.field.i = 5;
}
Expand All @@ -54,7 +36,7 @@ public void foo() {

// A generic class extending a generic class with both instantiated and
// uninstantiated parameters
class SuperclassMixed<U> extends TwoWrapper<U,IntWrapper> {
class SuperclassMixed<U> extends PairWrapper<U,IWrapper> {
public void foo(U value) {
this.first = value;
this.second.i = 5;
Expand Down Expand Up @@ -99,7 +81,7 @@ public void foo(U value) {
}
public Inner inner;

class InnerGen<T> extends TwoWrapper<U,T> {
class InnerGen<T> extends PairWrapper<U,T> {
public void foo(U uvalue, T tvalue) {
this.first = uvalue;
this.second = tvalue;
Expand All @@ -113,11 +95,23 @@ class InnerThree extends Inner {
}
class SuperclassInnerUninstTest
{
SuperclassInnerUninst<IntWrapper> f;
SuperclassInnerUninst<IWrapper> f;
public void foo() {
IntWrapper x = new IntWrapper();
IWrapper x = new IWrapper(0);
f.inner.foo(x);
f.inner_gen.foo(x,true);
f.inner_three.foo(x);
}
}

class SuperclassUnsupported extends UnsupportedWrapper1<SuperclassUnsupported> {
public void foo() {
this.field = new SuperclassUnsupported();
}
}

class SuperclassOpaque extends OpaqueWrapper<IWrapper> {
public void foo() {
this.field.i = 5;
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified unit/goto-programs/goto_program_generics/GenericFields.class
Binary file not shown.
64 changes: 40 additions & 24 deletions unit/goto-programs/goto_program_generics/GenericFields.java
Original file line number Diff line number Diff line change
@@ -1,41 +1,25 @@
class SimpleWrapper<T> {
public T field;
public T[] array_field;

public int int_field;
}

class IWrapper {
public int i;
}

class PairWrapper<K, V> {
public K key;
public V value;
}

public class GenericFields
{
IWrapper field;
class SimpleGenericField {
SimpleWrapper<IWrapper> field_input;
Wrapper<IWrapper> field_input;
public void foo() {
field_input.field.i = 5;
field_input.array_field = new IWrapper[2];
}
}

class MultipleGenericFields {
SimpleWrapper<IWrapper> field_input1;
SimpleWrapper<IWrapper> field_input2;
Wrapper<IWrapper> field_input1;
Wrapper<IWrapper> field_input2;
public void foo() {
field_input1.field.i = 10;
field_input2.field.i = 20;
}
}

class NestedGenericFields {
SimpleWrapper<SimpleWrapper<IWrapper>> field_input1;
Wrapper<Wrapper<IWrapper>> field_input1;
public void foo() {
field_input1.field.field.i = 30;
}
Expand All @@ -44,19 +28,19 @@ public void foo() {
class PairGenericField {
PairWrapper<IWrapper, IWrapper> field_input;
public void foo() {
field_input.key.i = 40;
field_input.value.i = 50;
field_input.first.i = 40;
field_input.second.i = 50;
}
}

class GenericMethodParameter {
public void foo(SimpleWrapper<IWrapper> v) {
public void foo(Wrapper<IWrapper> v) {
v.field.i = 20;
}
}

class GenericMethodUninstantiatedParameter {
public <T> void foo_unspec(SimpleWrapper<T> v) {
public <T> void foo_unspec(Wrapper<T> v) {
v.int_field=10;
}
}
Expand Down Expand Up @@ -96,3 +80,35 @@ public void foo(A<Integer> v) {
}
}
}

// class that implements two generic interfaces
class InterfacesImplementation implements InterfaceWrapper<IWrapper>,
InterfacePairWrapper<IWrapper, IWrapper> {
public IWrapper method(IWrapper t) {
return t;
}
public IWrapper method(IWrapper t, IWrapper tt) {
if (t.i>0)
{
return t;
}
else
{
return tt;
}
}
}
class GenericFieldUnsupported {
public UnsupportedWrapper2<InterfacesImplementation> f;
public void foo() {
f.field.method(new IWrapper(0));
f.field.method(new IWrapper(0), new IWrapper(2));
}
}

class GenericFieldOpaque {
public OpaqueWrapper<IWrapper> f;
public void foo() {
f.field.i = 0;
}
}
46 changes: 46 additions & 0 deletions unit/goto-programs/goto_program_generics/GenericHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// int wrapper
class IWrapper {
public int i;
public IWrapper(int ii) {
i = ii;
}
}

// simple generic class
class Wrapper<T> {
public T field;
public T[] array_field;
public int int_field;
}

// generic class with two parameters
class PairWrapper<K, V> {
public K first;
public V second;
}

// simple generic interface
interface InterfaceWrapper<T> {
public T method(T t);
}

// generic interface with two parameters
interface InterfacePairWrapper<K, V> {
public K method(K k, V v);
}

// generic class with unsupported signature - generic bound
class UnsupportedWrapper1<T extends UnsupportedWrapper1<T>> {
public T field;
}

// generic class with unsupported signature - multiple bounds
class UnsupportedWrapper2<T extends InterfaceWrapper & InterfacePairWrapper>
{
public T field;
}

// generic opaque class, make sure the .class file is not available
class OpaqueWrapper<T> {
public T field;
}
Binary file modified unit/goto-programs/goto_program_generics/IWrapper.class
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified unit/goto-programs/goto_program_generics/InterfaceWrapper.class
Binary file not shown.
Binary file not shown.
Binary file modified unit/goto-programs/goto_program_generics/PairWrapper.class
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified unit/goto-programs/goto_program_generics/SuperclassInst.class
Binary file not shown.
Binary file modified unit/goto-programs/goto_program_generics/SuperclassInst2.class
Binary file not shown.
Binary file modified unit/goto-programs/goto_program_generics/SuperclassInst3.class
Binary file not shown.
Binary file modified unit/goto-programs/goto_program_generics/SuperclassMixed.class
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified unit/goto-programs/goto_program_generics/SuperclassUninst.class
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified unit/goto-programs/goto_program_generics/Wrapper.class
Binary file not shown.
Loading