Skip to content

Commit fe79891

Browse files
author
svorenova
committed
Parsing generic bases' information into the class symbol
1 parent 6b08870 commit fe79891

File tree

1 file changed

+97
-5
lines changed

1 file changed

+97
-5
lines changed

src/java_bytecode/java_bytecode_convert_class.cpp

Lines changed: 97 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,58 @@ 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+
const size_t start = signature.front() == '<'
100+
? find_closing_delimiter(signature, 0, '<', '>') + 1
101+
: 0;
102+
103+
// extract the superclass reference
104+
const std::string superclass_ref = signature.substr(
105+
start,
106+
find_closing_semi_colon_for_reference_type(signature, start) - start + 1);
107+
108+
// if the superclass is generic then the reference is of form
109+
// Lsuperclass-name<generic-types>;
110+
if(superclass_ref.substr(superclass_ref.length() - 2) == ">;")
111+
return superclass_ref;
112+
else
113+
return "";
114+
}
115+
116+
/// Auxiliary function to extract the generic interface reference of an
117+
/// interface with the specified name from the class signature. If the
118+
/// interface is not generic, it returns an empty string.
119+
/// \param signature Signature of the class
120+
/// \param interface_name The interface name
121+
/// \return Reference of the generic interface, or empty if the interface
122+
/// is not generic
123+
static std::string extract_generic_interface_reference(
124+
const std::string &signature,
125+
const std::string &interface_name)
126+
{
127+
if(signature.find("L" + interface_name + "<") != std::string::npos)
128+
{
129+
const size_t start = signature.find("L" + interface_name + "<");
130+
return signature.substr(
131+
start,
132+
find_closing_semi_colon_for_reference_type(signature, start) - start + 1);
133+
}
134+
else
135+
{
136+
return "";
137+
}
138+
}
139+
88140
void java_bytecode_convert_classt::convert(const classt &c)
89141
{
90142
std::string qualified_classname="java::"+id2string(c.name);
@@ -145,10 +197,28 @@ void java_bytecode_convert_classt::convert(const classt &c)
145197

146198
if(!c.extends.empty())
147199
{
148-
symbol_typet base("java::"+id2string(c.extends));
149-
class_type.add_base(base);
200+
const symbol_typet base("java::" + id2string(c.extends));
201+
202+
// if the superclass is generic then the class has the superclass reference
203+
// including the generic info in its signature
204+
// e.g., signature for class 'A<T>' that extends
205+
// 'Generic<Integer>' is '<T:Ljava/lang/Object;>LGeneric<LInteger;>;'
206+
if(
207+
c.signature.has_value() &&
208+
!extract_generic_superclass_reference(c.signature.value()).empty())
209+
{
210+
const java_generic_symbol_typet gen_base(
211+
base,
212+
extract_generic_superclass_reference(c.signature.value()),
213+
qualified_classname);
214+
class_type.add_base(gen_base);
215+
}
216+
else
217+
{
218+
class_type.add_base(base);
219+
}
150220
class_typet::componentt base_class_field;
151-
base_class_field.type()=base;
221+
base_class_field.type() = class_type.bases().at(0).type();
152222
base_class_field.set_name("@"+id2string(c.extends));
153223
base_class_field.set_base_name("@"+id2string(c.extends));
154224
base_class_field.set_pretty_name("@"+id2string(c.extends));
@@ -158,8 +228,30 @@ void java_bytecode_convert_classt::convert(const classt &c)
158228
// interfaces are recorded as bases
159229
for(const auto &interface : c.implements)
160230
{
161-
symbol_typet base("java::"+id2string(interface));
162-
class_type.add_base(base);
231+
const symbol_typet base("java::" + id2string(interface));
232+
233+
// if the interface is generic then the class has the interface reference
234+
// including the generic info in its signature
235+
// e.g., signature for class 'A' that implements
236+
// 'GenericInterface<Integer>' is 'Ljava/lang/Object;
237+
// LGenericInterface<LInteger;>;'
238+
if(
239+
c.signature.has_value() &&
240+
!extract_generic_interface_reference(
241+
c.signature.value(), id2string(interface))
242+
.empty())
243+
{
244+
const java_generic_symbol_typet gen_base(
245+
base,
246+
extract_generic_interface_reference(
247+
c.signature.value(), id2string(interface)),
248+
qualified_classname);
249+
class_type.add_base(gen_base);
250+
}
251+
else
252+
{
253+
class_type.add_base(base);
254+
}
163255
}
164256

165257
// produce class symbol

0 commit comments

Comments
 (0)