2727#include < util/std_expr.h>
2828
2929#include < linking/zero_initializer.h>
30+ #include < util/suffix.h>
3031
3132class 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+
88166void 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
@@ -598,6 +708,15 @@ static void find_and_replace_parameters(
598708 find_and_replace_parameters (argument, replacement_parameters);
599709 }
600710 }
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+ }
601720}
602721
603722// / 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(
675794 find_and_replace_parameters (
676795 field.type (), implicit_generic_type_parameters);
677796 }
797+
798+ for (auto &base : class_type.bases ())
799+ {
800+ find_and_replace_parameters (
801+ base.type (), implicit_generic_type_parameters);
802+ }
678803 }
679804}
0 commit comments