Skip to content

Commit a619e48

Browse files
author
Thomas Kiley
authored
Merge pull request diffblue#1763 from jeannielynnmoulton/base_class_info_tg1287
[TG-1287] Parsing generic information of base classes
2 parents 0b8dd57 + 50dcec8 commit a619e48

33 files changed

+945
-29
lines changed

src/java_bytecode/java_bytecode_convert_class.cpp

+130-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
@@ -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
}

src/java_bytecode/java_types.h

+59
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,65 @@ to_java_specialized_generic_class_type(typet &type)
522522
return static_cast<const java_specialized_generic_class_typet &>(type);
523523
}
524524

525+
/// Type for a generic symbol, extends symbol_typet with a
526+
/// vector of java generic types.
527+
/// This is used to store the type of generic superclasses and interfaces.
528+
class java_generic_symbol_typet : public symbol_typet
529+
{
530+
public:
531+
typedef std::vector<reference_typet> generic_typest;
532+
533+
java_generic_symbol_typet(
534+
const symbol_typet &type,
535+
const std::string &base_ref,
536+
const std::string &class_name_prefix)
537+
: symbol_typet(type)
538+
{
539+
set(ID_C_java_generic_symbol, true);
540+
const typet &base_type = java_type_from_string(base_ref, class_name_prefix);
541+
PRECONDITION(is_java_generic_type(base_type));
542+
const java_generic_typet gen_base_type = to_java_generic_type(base_type);
543+
generic_types().insert(
544+
generic_types().end(),
545+
gen_base_type.generic_type_arguments().begin(),
546+
gen_base_type.generic_type_arguments().end());
547+
}
548+
549+
const generic_typest &generic_types() const
550+
{
551+
return (const generic_typest &)(find(ID_generic_types).get_sub());
552+
}
553+
554+
generic_typest &generic_types()
555+
{
556+
return (generic_typest &)(add(ID_generic_types).get_sub());
557+
}
558+
};
559+
560+
/// \param type: the type to check
561+
/// \return true if the type is a symbol type with generics
562+
inline bool is_java_generic_symbol_type(const typet &type)
563+
{
564+
return type.get_bool(ID_C_java_generic_symbol);
565+
}
566+
567+
/// \param type: the type to convert
568+
/// \return the converted type
569+
inline const java_generic_symbol_typet &
570+
to_java_generic_symbol_type(const typet &type)
571+
{
572+
PRECONDITION(is_java_generic_symbol_type(type));
573+
return static_cast<const java_generic_symbol_typet &>(type);
574+
}
575+
576+
/// \param type: the type to convert
577+
/// \return the converted type
578+
inline java_generic_symbol_typet &to_java_generic_symbol_type(typet &type)
579+
{
580+
PRECONDITION(is_java_generic_symbol_type(type));
581+
return static_cast<java_generic_symbol_typet &>(type);
582+
}
583+
525584
/// Take a signature string and remove everything in angle brackets allowing for
526585
/// the type to be parsed normally, for example
527586
/// `java.util.HashSet<java.lang.Integer>` will be turned into

src/util/irep_ids.def

+1
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,7 @@ IREP_ID_TWO(C_java_generic_type, #java_generic_type)
832832
IREP_ID_TWO(C_java_generics_class_type, #java_generics_class_type)
833833
IREP_ID_TWO(C_specialized_generic_java_class, #specialized_generic_java_class)
834834
IREP_ID_TWO(C_java_implicitly_generic_class_type, #java_implicitly_generic_class_type)
835+
IREP_ID_TWO(C_java_generic_symbol, #java_generic_symbol)
835836
IREP_ID_TWO(generic_types, #generic_types)
836837
IREP_ID_TWO(implicit_generic_types, #implicit_generic_types)
837838
IREP_ID_TWO(type_variables, #type_variables)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

unit/java_bytecode/java_bytecode_parse_generics/DerivedGenericInst.java

-4
This file was deleted.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

unit/java_bytecode/java_bytecode_parse_generics/DerivedGenericUninst.java

-4
This file was deleted.
Binary file not shown.

0 commit comments

Comments
 (0)