@@ -85,6 +85,79 @@ class java_bytecode_convert_classt:public messaget
85
85
static void add_array_types (symbol_tablet &symbol_table);
86
86
};
87
87
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
+
88
161
void java_bytecode_convert_classt::convert (const classt &c)
89
162
{
90
163
std::string qualified_classname=" java::" +id2string (c.name );
@@ -145,10 +218,27 @@ void java_bytecode_convert_classt::convert(const classt &c)
145
218
146
219
if (!c.extends .empty ())
147
220
{
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
+ }
150
240
class_typet::componentt base_class_field;
151
- base_class_field.type ()=base ;
241
+ base_class_field.type () = class_type. bases (). at ( 0 ). type () ;
152
242
base_class_field.set_name (" @" +id2string (c.extends ));
153
243
base_class_field.set_base_name (" @" +id2string (c.extends ));
154
244
base_class_field.set_pretty_name (" @" +id2string (c.extends ));
@@ -158,8 +248,29 @@ void java_bytecode_convert_classt::convert(const classt &c)
158
248
// interfaces are recorded as bases
159
249
for (const auto &interface : c.implements )
160
250
{
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
+ }
163
274
}
164
275
165
276
// produce class symbol
0 commit comments