Skip to content

Commit d415e73

Browse files
author
svorenova
committed
Parsing generic bases' information into the class symbol
1 parent 58c93ef commit d415e73

File tree

3 files changed

+120
-9
lines changed

3 files changed

+120
-9
lines changed

src/java_bytecode/java_bytecode_convert_class.cpp

+116-5
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,79 @@ class java_bytecode_convert_classt:public messaget
8585
static void add_array_types(symbol_tablet &symbol_table);
8686
};
8787

88+
/// Auxiliary function to extract the generic superclass reference from the
89+
/// class signature. If the superclass is not generic, it returns an empty
90+
/// string.
91+
/// \param signature Signature of the class
92+
/// \return Reference of the generic superclass, or empty if the superclass
93+
/// is not generic
94+
static std::string
95+
extract_generic_superclass_reference(const std::string &signature)
96+
{
97+
// skip the (potential) list of generic parameters at the beginning of the
98+
// signature
99+
size_t start = 0;
100+
if(signature.front() == '<')
101+
{
102+
start = find_closing_delimiter(signature, 0, '<', '>') + 1;
103+
}
104+
105+
std::string superclass_ref = signature.substr(start);
106+
superclass_ref = superclass_ref.substr(
107+
0, find_closing_semi_colon_for_reference_type(superclass_ref, 0) + 1);
108+
109+
// if the superclass is generic then the reference is of form
110+
// Lsuperclass-name<generic-types>;
111+
if(superclass_ref.substr(superclass_ref.length() - 2) == ">;")
112+
return superclass_ref;
113+
else
114+
return "";
115+
}
116+
117+
/// Auxiliary function to extract the generic interface reference of an
118+
/// interface with the specified name from the class signature. If the
119+
/// interface is not generic, it returns an empty string.
120+
/// \param signature Signature of the class
121+
/// \param interface_name The interface name
122+
/// \return Reference of the generic interface, or empty if the interface
123+
/// is not generic
124+
static std::string extract_generic_interface_reference(
125+
const std::string &signature,
126+
const std::string &interface_name)
127+
{
128+
// skip the (potential) list of generic parameters at the beginning of the
129+
// signature
130+
size_t start = 0;
131+
if(signature.front() == '<')
132+
{
133+
start = find_closing_delimiter(signature, 0, '<', '>') + 1;
134+
}
135+
136+
// skip the superclass reference
137+
start = find_closing_semi_colon_for_reference_type(signature, start) + 1;
138+
139+
// iterate through the references of interfaces, find the one that matches
140+
// the interface_name and if it is generic, return the reference
141+
size_t end;
142+
std::string interface_ref;
143+
while(start < signature.length())
144+
{
145+
end = find_closing_semi_colon_for_reference_type(signature, start);
146+
interface_ref = signature.substr(start, end - start + 1);
147+
start = end + 1;
148+
if(has_prefix(interface_ref, "L" + interface_name))
149+
{
150+
if(has_prefix(interface_ref, "L" + interface_name + "<"))
151+
{
152+
// the interface is generic
153+
break;
154+
}
155+
interface_ref = "";
156+
}
157+
}
158+
return interface_ref;
159+
}
160+
88161
void java_bytecode_convert_classt::convert(const classt &c)
89162
{
90163
std::string qualified_classname="java::"+id2string(c.name);
@@ -145,10 +218,27 @@ void java_bytecode_convert_classt::convert(const classt &c)
145218

146219
if(!c.extends.empty())
147220
{
148-
symbol_typet base("java::"+id2string(c.extends));
149-
class_type.add_base(base);
221+
// if the superclass is generic then the class has the superclass reference
222+
// including the generic info in its signature
223+
// e.g., signature for class 'A' that extends
224+
// 'Generic<Integer>' is 'LGeneric<LInteger;>;'
225+
if(
226+
c.signature.has_value() &&
227+
!extract_generic_superclass_reference(c.signature.value()).empty())
228+
{
229+
java_generic_base_typet gen_base =
230+
java_generic_base_typet::build_from_ref(
231+
extract_generic_superclass_reference(c.signature.value()),
232+
qualified_classname);
233+
class_type.add_base(gen_base);
234+
}
235+
else
236+
{
237+
symbol_typet base("java::" + id2string(c.extends));
238+
class_type.add_base(base);
239+
}
150240
class_typet::componentt base_class_field;
151-
base_class_field.type()=base;
241+
base_class_field.type() = class_type.bases().at(0).type();
152242
base_class_field.set_name("@"+id2string(c.extends));
153243
base_class_field.set_base_name("@"+id2string(c.extends));
154244
base_class_field.set_pretty_name("@"+id2string(c.extends));
@@ -158,8 +248,29 @@ void java_bytecode_convert_classt::convert(const classt &c)
158248
// interfaces are recorded as bases
159249
for(const auto &interface : c.implements)
160250
{
161-
symbol_typet base("java::"+id2string(interface));
162-
class_type.add_base(base);
251+
// if the interface is generic then the class has the interface reference
252+
// including the generic info in its signature
253+
// e.g., signature for class 'A' that implements
254+
// 'GenericInterface<Integer>' is 'Ljava/lang/Object;
255+
// LGenericInterface<LInteger;>;'
256+
if(
257+
c.signature.has_value() &&
258+
!extract_generic_interface_reference(
259+
c.signature.value(), id2string(interface))
260+
.empty())
261+
{
262+
java_generic_base_typet gen_base =
263+
java_generic_base_typet::build_from_ref(
264+
extract_generic_interface_reference(
265+
c.signature.value(), id2string(interface)),
266+
qualified_classname);
267+
class_type.add_base(gen_base);
268+
}
269+
else
270+
{
271+
symbol_typet base("java::" + id2string(interface));
272+
class_type.add_base(base);
273+
}
163274
}
164275

165276
// produce class symbol

src/java_bytecode/java_types.cpp

-4
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,6 @@ std::vector<typet> parse_list_types(
2929
const char opening_bracket,
3030
const char closing_bracket);
3131

32-
size_t find_closing_semi_colon_for_reference_type(
33-
const std::string src,
34-
size_t starting_point = 0);
35-
3632
typet java_int_type()
3733
{
3834
return signedbv_typet(32);

src/java_bytecode/java_types.h

+4
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ bool is_reference_type(char t);
7171
// z boolean
7272
// a reference
7373

74+
size_t find_closing_semi_colon_for_reference_type(
75+
const std::string src,
76+
size_t starting_point = 0);
77+
7478
typet java_type_from_char(char t);
7579
typet java_type_from_string(
7680
const std::string &,

0 commit comments

Comments
 (0)