Skip to content

Generics support #1434

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 28 commits into from
Oct 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
31faaa6
Revert "Revert "TG-374 Feature/java support generics""
Sep 21, 2017
b2f57e8
Fixing handling the case of *
Sep 22, 2017
1bd95c0
Classes that aren't generic but inherit from a generic type have a si…
Sep 25, 2017
b59c659
When dealing with generic arrays we should treat them like ref arrays…
Sep 25, 2017
a60ead4
Correctly handle nested generic types
Sep 25, 2017
79f743b
Adding conversions for wild cards
Sep 25, 2017
2f7f695
Adding some useful debug info
Sep 25, 2017
7320c46
Correcting a typo
Sep 25, 2017
35cd160
Deal with generic methods
Sep 25, 2017
a2344f8
Extending the tests for the generic class
Sep 27, 2017
33afe48
Adding unit tests for parsing wild card functions
Sep 27, 2017
1dd221d
Correct handling of the java generic class signature
Sep 28, 2017
8c7f4e4
Adding unit test for java class that inherits from a generic class
Sep 28, 2017
85c1574
Applied use of utility function for loading a class file
Sep 29, 2017
de5c040
Adding tests for generic functions
Sep 29, 2017
e8c75ac
Adding unit test for generic array
Oct 2, 2017
2f7925d
Adding unit test for recursive generic class
Oct 2, 2017
04e55be
Reverting method descriptor loading
Oct 3, 2017
a9dc64d
Disabling part of the unit test for generic classes
Oct 4, 2017
3a1962f
Turning back on regression tests
Oct 4, 2017
8f527f8
Cleaning java files
Oct 2, 2017
4f305de
Handling wild card generics with exception
Oct 4, 2017
97e1b9a
Adding a warning and a commentary for unsupported generics, cleaning
Oct 4, 2017
cfb5212
Resolving name shadowing
Oct 9, 2017
e140bb7
Updating the calls of lookup method to reflect the new return type
Oct 9, 2017
608c6b6
Disabling part of the unit test for generic classes
Oct 9, 2017
8d54be1
Adding exception and tests for missing closing delimiter
Oct 9, 2017
b7aaad0
Removing signature parsing for local variables
Oct 9, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion regression/cbmc-java/iterator2/test.desc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CORE
iterator2.class
--cover location --unwind 3 --function iterator2.f
--cover location --unwind 3 --function iterator2.f
^EXIT=0$
^SIGNAL=0$
^.*SATISFIED$
Expand Down
3 changes: 1 addition & 2 deletions src/java_bytecode/ci_lazy_methods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ bool ci_lazy_methodst::operator()(
{
const irep_idt methodid="java::"+id2string(classname)+"."+
id2string(method.name)+":"+
id2string(method.signature);
id2string(method.descriptor);
method_worklist2.push_back(methodid);
}
}
Expand Down Expand Up @@ -505,4 +505,3 @@ irep_idt ci_lazy_methodst::get_virtual_method_target(
else
return irep_idt();
}

74 changes: 72 additions & 2 deletions src/java_bytecode/java_bytecode_convert_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Author: Daniel Kroening, [email protected]
#include "java_bytecode_language.h"
#include "java_utils.h"

#include <util/c_types.h>
#include <util/arith_tools.h>
#include <util/namespace.h>
#include <util/std_expr.h>
Expand Down Expand Up @@ -93,6 +94,33 @@ void java_bytecode_convert_classt::convert(const classt &c)
}

java_class_typet class_type;
if(c.signature.has_value() && c.signature.value()[0]=='<')
{
java_generics_class_typet generic_class_type;
#ifdef DEBUG
std::cout << "INFO: found generic class signature "
<< c.signature.value()
<< " in parsed class "
<< c.name << "\n";
#endif
try
{
const std::vector<typet> &generic_types=java_generic_type_from_string(
id2string(c.name),
c.signature.value());
for(const typet &t : generic_types)
{
generic_class_type.generic_types()
.push_back(to_java_generic_parameter(t));
}
class_type=generic_class_type;
}
catch(unsupported_java_class_signature_exceptiont)
{
warning() << "we currently don't support parsing for example double "
"bounded, recursive and wild card generics" << eom;
}
}

class_type.set_tag(c.name);
class_type.set(ID_base_name, c.name);
Expand Down Expand Up @@ -166,7 +194,7 @@ void java_bytecode_convert_classt::convert(const classt &c)
const irep_idt method_identifier=
id2string(qualified_classname)+
"."+id2string(method.name)+
":"+method.signature;
":"+method.descriptor;
// Always run the lazy pre-stage, as it symbol-table
// registers the function.
debug() << "Adding symbol: method '" << method_identifier << "'" << eom;
Expand All @@ -187,7 +215,49 @@ void java_bytecode_convert_classt::convert(
symbolt &class_symbol,
const fieldt &f)
{
typet field_type=java_type_from_string(f.signature);
typet field_type;
if(f.signature.has_value())
{
field_type=java_type_from_string_with_exception(
f.descriptor,
f.signature,
id2string(class_symbol.name));

/// this is for a free type variable, e.g., a field of the form `T f;`
if(is_java_generic_parameter(field_type))
{
#ifdef DEBUG
std::cout << "fieldtype: generic "
<< to_java_generic_parameter(field_type).type_variable()
.get_identifier()
<< " name " << f.name << "\n";
#endif
}

/// this is for a field that holds a generic type, wither with instantiated
/// or with free type variables, e.g., `List<T> l;` or `List<Integer> l;`
else if(is_java_generic_type(field_type))
{
java_generic_typet &with_gen_type=
to_java_generic_type(field_type);
#ifdef DEBUG
std::cout << "fieldtype: generic container type "
<< std::to_string(with_gen_type.generic_type_variables().size())
<< " type " << with_gen_type.id()
<< " name " << f.name
<< " subtype id " << with_gen_type.subtype().id() << "\n";
#endif
field_type=with_gen_type;
}

/// This case is not possible, a field is either a non-instantiated type
/// variable or a generics container type.
INVARIANT(
!is_java_generic_inst_parameter(field_type),
"Cannot be an instantiated type variable here.");
}
else
field_type=java_type_from_string(f.descriptor);

// is this a static field?
if(f.is_static)
Expand Down
18 changes: 14 additions & 4 deletions src/java_bytecode/java_bytecode_convert_method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ const exprt java_bytecode_convert_methodt::variable(
/// method conversion just yet. The caller should call
/// java_bytecode_convert_method later to give the symbol/method a body.
/// \par parameters: `class_symbol`: class this method belongs to
/// `method_identifier`: fully qualified method name, including type signature
/// `method_identifier`: fully qualified method name, including type descriptor
/// (e.g. "x.y.z.f:(I)")
/// `m`: parsed method object to convert
/// `symbol_table`: global symbol table (will be modified)
Expand All @@ -263,7 +263,7 @@ void java_bytecode_convert_method_lazy(
symbol_tablet &symbol_table)
{
symbolt method_symbol;
typet member_type=java_type_from_string(m.signature);
typet member_type=java_type_from_string(m.descriptor);

method_symbol.name=method_identifier;
method_symbol.base_name=m.base_name;
Expand Down Expand Up @@ -317,7 +317,7 @@ void java_bytecode_convert_methodt::convert(
// to retrieve the symbol (constructed by java_bytecode_convert_method_lazy)
// associated to the method
const irep_idt method_identifier=
id2string(class_symbol.name)+"."+id2string(m.name)+":"+m.signature;
id2string(class_symbol.name)+"."+id2string(m.name)+":"+m.descriptor;
method_id=method_identifier;

const symbolt &old_sym=*symbol_table.lookup(method_identifier);
Expand Down Expand Up @@ -350,7 +350,17 @@ void java_bytecode_convert_methodt::convert(
// Construct a fully qualified name for the parameter v,
// e.g. my.package.ClassName.myMethodName:(II)I::anIntParam, and then a
// symbol_exprt with the parameter and its type
typet t=java_type_from_string(v.signature);
typet t;
if(v.signature.has_value())
{
t=java_type_from_string_with_exception(
v.descriptor,
v.signature,
id2string(class_symbol.name));
}
else
t=java_type_from_string(v.descriptor);

std::ostringstream id_oss;
id_oss << method_id << "::" << v.name;
irep_idt identifier(id_oss.str());
Expand Down
7 changes: 4 additions & 3 deletions src/java_bytecode/java_bytecode_parse_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ void java_bytecode_parse_treet::classt::swap(
std::swap(other.is_public, is_public);
std::swap(other.is_protected, is_protected);
std::swap(other.is_private, is_private);
std::swap(other.signature, signature);
other.implements.swap(implements);
other.fields.swap(fields);
other.methods.swap(methods);
Expand Down Expand Up @@ -151,7 +152,7 @@ void java_bytecode_parse_treet::methodt::output(std::ostream &out) const
out << "synchronized ";

out << name;
out << " : " << signature;
out << " : " << descriptor;

out << '\n';

Expand Down Expand Up @@ -188,7 +189,7 @@ void java_bytecode_parse_treet::methodt::output(std::ostream &out) const
for(const auto &v : local_variable_table)
{
out << " " << v.index << ": " << v.name << ' '
<< v.signature << '\n';
<< v.descriptor << '\n';
}

out << '\n';
Expand All @@ -212,7 +213,7 @@ void java_bytecode_parse_treet::fieldt::output(std::ostream &out) const
out << "static ";

out << name;
out << " : " << signature << ';';
out << " : " << descriptor << ';';

out << '\n';
}
13 changes: 8 additions & 5 deletions src/java_bytecode/java_bytecode_parse_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Author: Daniel Kroening, [email protected]

#include <set>

#include <util/optional.h>
#include <util/std_code.h>
#include <util/std_types.h>

Expand Down Expand Up @@ -54,16 +55,17 @@ class java_bytecode_parse_treet
class membert
{
public:
std::string signature;
std::string descriptor;
optionalt<std::string> signature;
irep_idt name;
bool is_public, is_protected, is_private, is_static, is_final;
annotationst annotations;

virtual void output(std::ostream &out) const = 0;

membert():
is_public(false), is_protected(false), is_private(false),
is_static(false), is_final(false)
is_public(false), is_protected(false),
is_private(false), is_static(false), is_final(false)
{
}
};
Expand Down Expand Up @@ -100,7 +102,8 @@ class java_bytecode_parse_treet
{
public:
irep_idt name;
std::string signature;
std::string descriptor;
optionalt<std::string> signature;
std::size_t index;
std::size_t start_pc;
std::size_t length;
Expand Down Expand Up @@ -174,7 +177,7 @@ class java_bytecode_parse_treet

typedef std::list<irep_idt> implementst;
implementst implements;

optionalt<std::string> signature;
typedef std::list<fieldt> fieldst;
typedef std::list<methodt> methodst;
fieldst fields;
Expand Down
Loading