@@ -248,6 +248,69 @@ const exprt java_bytecode_convert_methodt::variable(
248248 }
249249}
250250
251+ // / Returns the member type for a method, based on signature or descriptor
252+ // / \param descriptor
253+ // / descriptor of the method
254+ // / \param signature
255+ // / signature of the method
256+ // / \param class_name
257+ // / string containing the name of the corresponding class
258+ // / \param method_name
259+ // / string containing the name of the method
260+ // / \param message_handler
261+ // / message handler to collect warnings
262+ // / \return
263+ // / the constructed member type
264+ typet member_type_lazy (const std::string &descriptor,
265+ const optionalt<std::string> &signature,
266+ const std::string &class_name,
267+ const std::string &method_name,
268+ message_handlert &message_handler)
269+ {
270+ // In order to construct the method type, we can either use signature or
271+ // descriptor. Since only signature contains the generics info, we want to
272+ // use signature whenever possible. We revert to using descriptor if (1) the
273+ // signature does not exist, (2) an unsupported generics are present or
274+ // (3) in the special case when the number of parameters in the descriptor
275+ // does not match the number of parameters in the signature - e.g. for
276+ // certain types of inner classes and enums (see unit tests for examples).
277+
278+ messaget message (message_handler);
279+
280+ typet member_type_from_descriptor=java_type_from_string (descriptor);
281+ INVARIANT (member_type_from_descriptor.id ()==ID_code, " Must be code type" );
282+ if (signature.has_value ())
283+ {
284+ try
285+ {
286+ typet member_type_from_signature=java_type_from_string (
287+ signature.value (),
288+ class_name);
289+ INVARIANT (member_type_from_signature.id ()==ID_code, " Must be code type" );
290+ if (to_code_type (member_type_from_signature).parameters ().size ()==
291+ to_code_type (member_type_from_descriptor).parameters ().size ())
292+ {
293+ return member_type_from_signature;
294+ }
295+ else
296+ {
297+ message.warning () << " method: " << class_name << " ." << method_name
298+ << " \n signature: " << signature.value () << " \n descriptor: "
299+ << descriptor << " \n different number of parameters, reverting to "
300+ " descriptor" << message.eom ;
301+ }
302+ }
303+ catch (unsupported_java_class_signature_exceptiont &e)
304+ {
305+ message.warning () << " method: " << class_name << " ." << method_name
306+ << " \n could not parse signature: " << signature.value () << " \n "
307+ << e.what () << " \n " << " reverting to descriptor: "
308+ << descriptor << message.eom ;
309+ }
310+ }
311+ return member_type_from_descriptor;
312+ }
313+
251314// / This creates a method symbol in the symtab, but doesn't actually perform
252315// / method conversion just yet. The caller should call
253316// / java_bytecode_convert_method later to give the symbol/method a body.
@@ -256,14 +319,22 @@ const exprt java_bytecode_convert_methodt::variable(
256319// / (e.g. "x.y.z.f:(I)")
257320// / `m`: parsed method object to convert
258321// / `symbol_table`: global symbol table (will be modified)
322+ // / `message_handler`: message handler to collect warnings
259323void java_bytecode_convert_method_lazy (
260324 const symbolt &class_symbol,
261325 const irep_idt &method_identifier,
262326 const java_bytecode_parse_treet::methodt &m,
263- symbol_tablet &symbol_table)
327+ symbol_tablet &symbol_table,
328+ message_handlert &message_handler)
264329{
265330 symbolt method_symbol;
266- typet member_type=java_type_from_string (m.descriptor );
331+
332+ typet member_type=member_type_lazy (
333+ m.descriptor ,
334+ m.signature ,
335+ id2string (class_symbol.name ),
336+ id2string (m.base_name ),
337+ message_handler);
267338
268339 method_symbol.name =method_identifier;
269340 method_symbol.base_name =m.base_name ;
0 commit comments