Skip to content

Commit e618169

Browse files
author
Thomas Kiley
authored
Merge pull request #1434 from svorenova/generics_support
Generics support
2 parents 68e4d6b + b7aaad0 commit e618169

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1692
-50
lines changed

regression/cbmc-java/iterator2/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
CORE
22
iterator2.class
3-
--cover location --unwind 3 --function iterator2.f
3+
--cover location --unwind 3 --function iterator2.f
44
^EXIT=0$
55
^SIGNAL=0$
66
^.*SATISFIED$

src/java_bytecode/ci_lazy_methods.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ bool ci_lazy_methodst::operator()(
7979
{
8080
const irep_idt methodid="java::"+id2string(classname)+"."+
8181
id2string(method.name)+":"+
82-
id2string(method.signature);
82+
id2string(method.descriptor);
8383
method_worklist2.push_back(methodid);
8484
}
8585
}
@@ -505,4 +505,3 @@ irep_idt ci_lazy_methodst::get_virtual_method_target(
505505
else
506506
return irep_idt();
507507
}
508-

src/java_bytecode/java_bytecode_convert_class.cpp

+72-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Author: Daniel Kroening, [email protected]
2121
#include "java_bytecode_language.h"
2222
#include "java_utils.h"
2323

24+
#include <util/c_types.h>
2425
#include <util/arith_tools.h>
2526
#include <util/namespace.h>
2627
#include <util/std_expr.h>
@@ -93,6 +94,33 @@ void java_bytecode_convert_classt::convert(const classt &c)
9394
}
9495

9596
java_class_typet class_type;
97+
if(c.signature.has_value() && c.signature.value()[0]=='<')
98+
{
99+
java_generics_class_typet generic_class_type;
100+
#ifdef DEBUG
101+
std::cout << "INFO: found generic class signature "
102+
<< c.signature.value()
103+
<< " in parsed class "
104+
<< c.name << "\n";
105+
#endif
106+
try
107+
{
108+
const std::vector<typet> &generic_types=java_generic_type_from_string(
109+
id2string(c.name),
110+
c.signature.value());
111+
for(const typet &t : generic_types)
112+
{
113+
generic_class_type.generic_types()
114+
.push_back(to_java_generic_parameter(t));
115+
}
116+
class_type=generic_class_type;
117+
}
118+
catch(unsupported_java_class_signature_exceptiont)
119+
{
120+
warning() << "we currently don't support parsing for example double "
121+
"bounded, recursive and wild card generics" << eom;
122+
}
123+
}
96124

97125
class_type.set_tag(c.name);
98126
class_type.set(ID_base_name, c.name);
@@ -166,7 +194,7 @@ void java_bytecode_convert_classt::convert(const classt &c)
166194
const irep_idt method_identifier=
167195
id2string(qualified_classname)+
168196
"."+id2string(method.name)+
169-
":"+method.signature;
197+
":"+method.descriptor;
170198
// Always run the lazy pre-stage, as it symbol-table
171199
// registers the function.
172200
debug() << "Adding symbol: method '" << method_identifier << "'" << eom;
@@ -187,7 +215,49 @@ void java_bytecode_convert_classt::convert(
187215
symbolt &class_symbol,
188216
const fieldt &f)
189217
{
190-
typet field_type=java_type_from_string(f.signature);
218+
typet field_type;
219+
if(f.signature.has_value())
220+
{
221+
field_type=java_type_from_string_with_exception(
222+
f.descriptor,
223+
f.signature,
224+
id2string(class_symbol.name));
225+
226+
/// this is for a free type variable, e.g., a field of the form `T f;`
227+
if(is_java_generic_parameter(field_type))
228+
{
229+
#ifdef DEBUG
230+
std::cout << "fieldtype: generic "
231+
<< to_java_generic_parameter(field_type).type_variable()
232+
.get_identifier()
233+
<< " name " << f.name << "\n";
234+
#endif
235+
}
236+
237+
/// this is for a field that holds a generic type, wither with instantiated
238+
/// or with free type variables, e.g., `List<T> l;` or `List<Integer> l;`
239+
else if(is_java_generic_type(field_type))
240+
{
241+
java_generic_typet &with_gen_type=
242+
to_java_generic_type(field_type);
243+
#ifdef DEBUG
244+
std::cout << "fieldtype: generic container type "
245+
<< std::to_string(with_gen_type.generic_type_variables().size())
246+
<< " type " << with_gen_type.id()
247+
<< " name " << f.name
248+
<< " subtype id " << with_gen_type.subtype().id() << "\n";
249+
#endif
250+
field_type=with_gen_type;
251+
}
252+
253+
/// This case is not possible, a field is either a non-instantiated type
254+
/// variable or a generics container type.
255+
INVARIANT(
256+
!is_java_generic_inst_parameter(field_type),
257+
"Cannot be an instantiated type variable here.");
258+
}
259+
else
260+
field_type=java_type_from_string(f.descriptor);
191261

192262
// is this a static field?
193263
if(f.is_static)

src/java_bytecode/java_bytecode_convert_method.cpp

+14-4
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ const exprt java_bytecode_convert_methodt::variable(
252252
/// method conversion just yet. The caller should call
253253
/// java_bytecode_convert_method later to give the symbol/method a body.
254254
/// \par parameters: `class_symbol`: class this method belongs to
255-
/// `method_identifier`: fully qualified method name, including type signature
255+
/// `method_identifier`: fully qualified method name, including type descriptor
256256
/// (e.g. "x.y.z.f:(I)")
257257
/// `m`: parsed method object to convert
258258
/// `symbol_table`: global symbol table (will be modified)
@@ -263,7 +263,7 @@ void java_bytecode_convert_method_lazy(
263263
symbol_tablet &symbol_table)
264264
{
265265
symbolt method_symbol;
266-
typet member_type=java_type_from_string(m.signature);
266+
typet member_type=java_type_from_string(m.descriptor);
267267

268268
method_symbol.name=method_identifier;
269269
method_symbol.base_name=m.base_name;
@@ -317,7 +317,7 @@ void java_bytecode_convert_methodt::convert(
317317
// to retrieve the symbol (constructed by java_bytecode_convert_method_lazy)
318318
// associated to the method
319319
const irep_idt method_identifier=
320-
id2string(class_symbol.name)+"."+id2string(m.name)+":"+m.signature;
320+
id2string(class_symbol.name)+"."+id2string(m.name)+":"+m.descriptor;
321321
method_id=method_identifier;
322322

323323
const symbolt &old_sym=*symbol_table.lookup(method_identifier);
@@ -350,7 +350,17 @@ void java_bytecode_convert_methodt::convert(
350350
// Construct a fully qualified name for the parameter v,
351351
// e.g. my.package.ClassName.myMethodName:(II)I::anIntParam, and then a
352352
// symbol_exprt with the parameter and its type
353-
typet t=java_type_from_string(v.signature);
353+
typet t;
354+
if(v.signature.has_value())
355+
{
356+
t=java_type_from_string_with_exception(
357+
v.descriptor,
358+
v.signature,
359+
id2string(class_symbol.name));
360+
}
361+
else
362+
t=java_type_from_string(v.descriptor);
363+
354364
std::ostringstream id_oss;
355365
id_oss << method_id << "::" << v.name;
356366
irep_idt identifier(id_oss.str());

src/java_bytecode/java_bytecode_parse_tree.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ void java_bytecode_parse_treet::classt::swap(
2828
std::swap(other.is_public, is_public);
2929
std::swap(other.is_protected, is_protected);
3030
std::swap(other.is_private, is_private);
31+
std::swap(other.signature, signature);
3132
other.implements.swap(implements);
3233
other.fields.swap(fields);
3334
other.methods.swap(methods);
@@ -151,7 +152,7 @@ void java_bytecode_parse_treet::methodt::output(std::ostream &out) const
151152
out << "synchronized ";
152153

153154
out << name;
154-
out << " : " << signature;
155+
out << " : " << descriptor;
155156

156157
out << '\n';
157158

@@ -188,7 +189,7 @@ void java_bytecode_parse_treet::methodt::output(std::ostream &out) const
188189
for(const auto &v : local_variable_table)
189190
{
190191
out << " " << v.index << ": " << v.name << ' '
191-
<< v.signature << '\n';
192+
<< v.descriptor << '\n';
192193
}
193194

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

214215
out << name;
215-
out << " : " << signature << ';';
216+
out << " : " << descriptor << ';';
216217

217218
out << '\n';
218219
}

src/java_bytecode/java_bytecode_parse_tree.h

+8-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Author: Daniel Kroening, [email protected]
1212

1313
#include <set>
1414

15+
#include <util/optional.h>
1516
#include <util/std_code.h>
1617
#include <util/std_types.h>
1718

@@ -54,16 +55,17 @@ class java_bytecode_parse_treet
5455
class membert
5556
{
5657
public:
57-
std::string signature;
58+
std::string descriptor;
59+
optionalt<std::string> signature;
5860
irep_idt name;
5961
bool is_public, is_protected, is_private, is_static, is_final;
6062
annotationst annotations;
6163

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

6466
membert():
65-
is_public(false), is_protected(false), is_private(false),
66-
is_static(false), is_final(false)
67+
is_public(false), is_protected(false),
68+
is_private(false), is_static(false), is_final(false)
6769
{
6870
}
6971
};
@@ -100,7 +102,8 @@ class java_bytecode_parse_treet
100102
{
101103
public:
102104
irep_idt name;
103-
std::string signature;
105+
std::string descriptor;
106+
optionalt<std::string> signature;
104107
std::size_t index;
105108
std::size_t start_pc;
106109
std::size_t length;
@@ -174,7 +177,7 @@ class java_bytecode_parse_treet
174177

175178
typedef std::list<irep_idt> implementst;
176179
implementst implements;
177-
180+
optionalt<std::string> signature;
178181
typedef std::list<fieldt> fieldst;
179182
typedef std::list<methodt> methodst;
180183
fieldst fields;

0 commit comments

Comments
 (0)