27
27
#include < util/std_expr.h>
28
28
29
29
#include < linking/zero_initializer.h>
30
+ #include < util/suffix.h>
30
31
31
32
class java_bytecode_convert_classt :public messaget
32
33
{
@@ -85,6 +86,83 @@ class java_bytecode_convert_classt:public messaget
85
86
static void add_array_types (symbol_tablet &symbol_table);
86
87
};
87
88
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
+
88
166
void java_bytecode_convert_classt::convert (const classt &c)
89
167
{
90
168
std::string qualified_classname=" java::" +id2string (c.name );
@@ -145,10 +223,26 @@ void java_bytecode_convert_classt::convert(const classt &c)
145
223
146
224
if (!c.extends .empty ())
147
225
{
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
+ }
150
244
class_typet::componentt base_class_field;
151
- base_class_field.type ()=base ;
245
+ base_class_field.type () = class_type. bases (). at ( 0 ). type () ;
152
246
base_class_field.set_name (" @" +id2string (c.extends ));
153
247
base_class_field.set_base_name (" @" +id2string (c.extends ));
154
248
base_class_field.set_pretty_name (" @" +id2string (c.extends ));
@@ -158,8 +252,24 @@ void java_bytecode_convert_classt::convert(const classt &c)
158
252
// interfaces are recorded as bases
159
253
for (const auto &interface : c.implements )
160
254
{
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
+ }
163
273
}
164
274
165
275
// produce class symbol
@@ -598,6 +708,15 @@ static void find_and_replace_parameters(
598
708
find_and_replace_parameters (argument, replacement_parameters);
599
709
}
600
710
}
711
+ else if (is_java_generic_symbol_type (type))
712
+ {
713
+ java_generic_symbol_typet &generic_base = to_java_generic_symbol_type (type);
714
+ std::vector<reference_typet> &gen_types = generic_base.generic_types ();
715
+ for (auto &gen_type : gen_types)
716
+ {
717
+ find_and_replace_parameters (gen_type, replacement_parameters);
718
+ }
719
+ }
601
720
}
602
721
603
722
// / Checks if the class is implicitly generic, i.e., it is an inner class of
@@ -675,5 +794,11 @@ void mark_java_implicitly_generic_class_type(
675
794
find_and_replace_parameters (
676
795
field.type (), implicit_generic_type_parameters);
677
796
}
797
+
798
+ for (auto &base : class_type.bases ())
799
+ {
800
+ find_and_replace_parameters (
801
+ base.type (), implicit_generic_type_parameters);
802
+ }
678
803
}
679
804
}
0 commit comments