Skip to content

Commit 6d691d7

Browse files
author
svorenova
committed
Parsing generic bases' information into the class symbol
1 parent 7d041f0 commit 6d691d7

File tree

1 file changed

+115
-5
lines changed

1 file changed

+115
-5
lines changed

src/java_bytecode/java_bytecode_convert_class.cpp

+115-5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Author: Daniel Kroening, [email protected]
2727
#include <util/std_expr.h>
2828

2929
#include <linking/zero_initializer.h>
30+
#include <util/suffix.h>
3031

3132
class java_bytecode_convert_classt:public messaget
3233
{
@@ -85,6 +86,83 @@ class java_bytecode_convert_classt:public messaget
8586
static void add_array_types(symbol_tablet &symbol_table);
8687
};
8788

89+
/// Auxiliary function to extract the generic superclass reference from the
90+
/// class signature. If the signature is empty or the superclass is not generic
91+
/// it returns empty.
92+
/// Example:
93+
/// - class: A<T> extends B<T, Integer> implements C, D<T>
94+
/// - signature: <T:Ljava/lang/Object;>B<TT;Ljava/lang/Integer;>;LC;LD<TT;>;
95+
/// - returned superclass reference: B<TT;Ljava/lang/Integer;>;
96+
/// \param signature Signature of the class
97+
/// \return Reference of the generic superclass, or empty if the superclass
98+
/// is not generic
99+
static optionalt<std::string>
100+
extract_generic_superclass_reference(const optionalt<std::string> &signature)
101+
{
102+
if(signature.has_value())
103+
{
104+
// skip the (potential) list of generic parameters at the beginning of the
105+
// signature
106+
const size_t start =
107+
signature.value().front() == '<'
108+
? find_closing_delimiter(signature.value(), 0, '<', '>') + 1
109+
: 0;
110+
111+
// extract the superclass reference
112+
const size_t end =
113+
find_closing_semi_colon_for_reference_type(signature.value(), start);
114+
const std::string superclass_ref =
115+
signature.value().substr(start, (end - start) + 1);
116+
117+
// if the superclass is generic then the reference is of form
118+
// Lsuperclass-name<generic-types;>;
119+
if(has_suffix(superclass_ref, ">;"))
120+
return superclass_ref;
121+
}
122+
return {};
123+
}
124+
125+
/// Auxiliary function to extract the generic interface reference of an
126+
/// interface with the specified name from the class signature. If the
127+
/// signature is empty or the interface is not generic it returns empty.
128+
/// Example:
129+
/// - class: A<T> extends B<T, Integer> implements C, D<T>
130+
/// - signature: <T:Ljava/lang/Object;>B<TT;Ljava/lang/Integer;>;LC;LD<TT;>;
131+
/// - returned interface reference for C: LC;
132+
/// - returned interface reference for D: LD<TT;>;
133+
/// \param signature Signature of the class
134+
/// \param interface_name The interface name
135+
/// \return Reference of the generic interface, or empty if the interface
136+
/// is not generic
137+
static optionalt<std::string> extract_generic_interface_reference(
138+
const optionalt<std::string> &signature,
139+
const std::string &interface_name)
140+
{
141+
if(signature.has_value())
142+
{
143+
// skip the (potential) list of generic parameters at the beginning of the
144+
// signature
145+
size_t start =
146+
signature.value().front() == '<'
147+
? find_closing_delimiter(signature.value(), 0, '<', '>') + 1
148+
: 0;
149+
150+
// skip the superclass reference (if there is at least one interface
151+
// reference in the signature, then there is a superclass reference)
152+
start =
153+
find_closing_semi_colon_for_reference_type(signature.value(), start) + 1;
154+
155+
start = signature.value().find("L" + interface_name + "<", start);
156+
if(start != std::string::npos)
157+
{
158+
const size_t &end =
159+
find_closing_semi_colon_for_reference_type(signature.value(), start);
160+
return signature.value().substr(start, (end - start) + 1);
161+
}
162+
}
163+
return {};
164+
}
165+
88166
void java_bytecode_convert_classt::convert(const classt &c)
89167
{
90168
std::string qualified_classname="java::"+id2string(c.name);
@@ -145,10 +223,26 @@ void java_bytecode_convert_classt::convert(const classt &c)
145223

146224
if(!c.extends.empty())
147225
{
148-
symbol_typet base("java::"+id2string(c.extends));
149-
class_type.add_base(base);
226+
const symbol_typet base("java::" + id2string(c.extends));
227+
228+
// if the superclass is generic then the class has the superclass reference
229+
// including the generic info in its signature
230+
// e.g., signature for class 'A<T>' that extends
231+
// 'Generic<Integer>' is '<T:Ljava/lang/Object;>LGeneric<LInteger;>;'
232+
const optionalt<std::string> &superclass_ref =
233+
extract_generic_superclass_reference(c.signature);
234+
if(superclass_ref.has_value())
235+
{
236+
const java_generic_symbol_typet generic_base(
237+
base, superclass_ref.value(), qualified_classname);
238+
class_type.add_base(generic_base);
239+
}
240+
else
241+
{
242+
class_type.add_base(base);
243+
}
150244
class_typet::componentt base_class_field;
151-
base_class_field.type()=base;
245+
base_class_field.type() = class_type.bases().at(0).type();
152246
base_class_field.set_name("@"+id2string(c.extends));
153247
base_class_field.set_base_name("@"+id2string(c.extends));
154248
base_class_field.set_pretty_name("@"+id2string(c.extends));
@@ -158,8 +252,24 @@ void java_bytecode_convert_classt::convert(const classt &c)
158252
// interfaces are recorded as bases
159253
for(const auto &interface : c.implements)
160254
{
161-
symbol_typet base("java::"+id2string(interface));
162-
class_type.add_base(base);
255+
const symbol_typet base("java::" + id2string(interface));
256+
257+
// if the interface is generic then the class has the interface reference
258+
// including the generic info in its signature
259+
// e.g., signature for class 'A implements GenericInterface<Integer>' is
260+
// 'Ljava/lang/Object;LGenericInterface<LInteger;>;'
261+
const optionalt<std::string> interface_ref =
262+
extract_generic_interface_reference(c.signature, id2string(interface));
263+
if(interface_ref.has_value())
264+
{
265+
const java_generic_symbol_typet generic_base(
266+
base, interface_ref.value(), qualified_classname);
267+
class_type.add_base(generic_base);
268+
}
269+
else
270+
{
271+
class_type.add_base(base);
272+
}
163273
}
164274

165275
// produce class symbol

0 commit comments

Comments
 (0)