Skip to content

Commit 161787b

Browse files
author
Matthias Güdemann
authored
Merge pull request #1597 from diffblue/bugfix/add_generic_type_args_to_dependencies
TG-1212 Bugfix/add generic type args to dependencies
2 parents e707be3 + e8f5e08 commit 161787b

13 files changed

+157
-9
lines changed
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
class IWrapper {
2+
public int i;
3+
}
4+
5+
class FWrapper {
6+
}
7+
8+
class AWrapper {
9+
}
10+
11+
class SimpleWrapper<T> {
12+
}
13+
14+
public class GenericFields
15+
{
16+
class SimpleGenericField {
17+
// IWrapper field; // for this to work, uncomment this line
18+
SimpleWrapper<IWrapper> field_input;
19+
public void foo() {
20+
}
21+
SimpleWrapper<IWrapper> f(SimpleWrapper<FWrapper> s, SimpleWrapper<AWrapper []> a) {
22+
return new SimpleWrapper<>();
23+
}
24+
}
25+
}
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
GenericFields$SimpleGenericField.class
3+
--cover location --function GenericFields\$SimpleGenericField.foo --verbosity 10
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
Reading class AWrapper
7+
Reading class FWrapper
8+
Reading class IWrapper

src/java_bytecode/java_bytecode_convert_method.cpp

-9
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,6 @@ static bool operator==(const irep_idt &what, const patternt &pattern)
116116
return pattern==what;
117117
}
118118

119-
static irep_idt strip_java_namespace_prefix(const irep_idt to_strip)
120-
{
121-
const std::string to_strip_str=id2string(to_strip);
122-
const std::string prefix="java::";
123-
124-
PRECONDITION(has_prefix(to_strip_str, prefix));
125-
return to_strip_str.substr(prefix.size(), std::string::npos);
126-
}
127-
128119
// name contains <init> or <clinit>
129120
bool java_bytecode_convert_methodt::is_constructor(
130121
const class_typet::methodt &method)

src/java_bytecode/java_bytecode_parser.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,11 @@ void java_bytecode_parsert::get_class_refs()
343343
field.descriptor,
344344
field.signature,
345345
"java::"+id2string(parse_tree.parsed_class.name));
346+
347+
// add generic type args to class refs as dependencies, same below for
348+
// method types and entries from the local variable type table
349+
get_dependencies_from_generic_parameters(
350+
field_type, parse_tree.class_refs);
346351
}
347352
else
348353
field_type=java_type_from_string(field.descriptor);
@@ -359,6 +364,8 @@ void java_bytecode_parsert::get_class_refs()
359364
method.descriptor,
360365
method.signature,
361366
"java::"+id2string(parse_tree.parsed_class.name));
367+
get_dependencies_from_generic_parameters(
368+
method_type, parse_tree.class_refs);
362369
}
363370
else
364371
method_type=java_type_from_string(method.descriptor);
@@ -373,6 +380,8 @@ void java_bytecode_parsert::get_class_refs()
373380
var.descriptor,
374381
var.signature,
375382
"java::"+id2string(parse_tree.parsed_class.name));
383+
get_dependencies_from_generic_parameters(
384+
var_type, parse_tree.class_refs);
376385
}
377386
else
378387
var_type=java_type_from_string(var.descriptor);
@@ -1356,6 +1365,9 @@ void java_bytecode_parsert::rclass_attribute(classt &parsed_class)
13561365
{
13571366
u2 signature_index=read_u2();
13581367
parsed_class.signature=id2string(pool_entry(signature_index).s);
1368+
get_dependencies_from_generic_parameters(
1369+
parsed_class.signature.value(),
1370+
parse_tree.class_refs);
13591371
}
13601372
else if(attribute_name=="RuntimeInvisibleAnnotations" ||
13611373
attribute_name=="RuntimeVisibleAnnotations")

src/java_bytecode/java_types.cpp

+90
Original file line numberDiff line numberDiff line change
@@ -715,3 +715,93 @@ bool is_valid_java_array(const struct_typet &type)
715715
length_component_valid &&
716716
data_component_valid;
717717
}
718+
719+
void get_dependencies_from_generic_parameters_rec(
720+
const typet &t,
721+
std::set<irep_idt> &refs)
722+
{
723+
// Java generic type that holds different types in its type arguments
724+
if(is_java_generic_type(t))
725+
{
726+
for(const auto type_arg : to_java_generic_type(t).generic_type_arguments())
727+
get_dependencies_from_generic_parameters_rec(type_arg, refs);
728+
}
729+
730+
// Java reference type
731+
else if(t.id() == ID_pointer)
732+
{
733+
get_dependencies_from_generic_parameters_rec(t.subtype(), refs);
734+
}
735+
736+
// method type with parameters and return value
737+
else if(t.id() == ID_code)
738+
{
739+
const code_typet &c = to_code_type(t);
740+
get_dependencies_from_generic_parameters_rec(c.return_type(), refs);
741+
for(const auto &param : c.parameters())
742+
get_dependencies_from_generic_parameters_rec(param.type(), refs);
743+
}
744+
745+
// symbol type
746+
else if(t.id() == ID_symbol)
747+
{
748+
const symbol_typet &symbol_type = to_symbol_type(t);
749+
const irep_idt class_name(symbol_type.get_identifier());
750+
if(is_java_array_tag(class_name))
751+
{
752+
get_dependencies_from_generic_parameters(
753+
java_array_element_type(symbol_type), refs);
754+
}
755+
else
756+
refs.insert(strip_java_namespace_prefix(class_name));
757+
}
758+
}
759+
760+
/// Collect information about generic type parameters from a given
761+
/// signature. This is used to get information about class dependencies that
762+
/// must be loaded but only appear as generic type argument, not as a field
763+
/// reference.
764+
/// \param signature: the string representation of the signature to analyze
765+
/// \param refs [out]: the set to insert the names of the found dependencies
766+
void get_dependencies_from_generic_parameters(
767+
const std::string &signature,
768+
std::set<irep_idt> &refs)
769+
{
770+
try
771+
{
772+
// class signature with bounds
773+
if(signature[0] == '<')
774+
{
775+
const std::vector<typet> types = java_generic_type_from_string(
776+
erase_type_arguments(signature), signature);
777+
778+
for(const auto &t : types)
779+
get_dependencies_from_generic_parameters_rec(t, refs);
780+
}
781+
782+
// class signature without bounds and without wildcards
783+
else if(signature.find('*') == std::string::npos)
784+
{
785+
get_dependencies_from_generic_parameters_rec(
786+
java_type_from_string(signature, erase_type_arguments(signature)),
787+
refs);
788+
}
789+
}
790+
catch(unsupported_java_class_signature_exceptiont &)
791+
{
792+
// skip for now, if we cannot parse it, we cannot detect which additional
793+
// classes should be loaded as dependencies
794+
}
795+
}
796+
797+
/// Collect information about generic type parameters from a given type. This is
798+
/// used to get information about class dependencies that must be loaded but
799+
/// only appear as generic type argument, not as a field reference.
800+
/// \param t: the type to analyze
801+
/// \param refs [out]: the set to insert the names of the found dependencies
802+
void get_dependencies_from_generic_parameters(
803+
const typet &t,
804+
std::set<irep_idt> &refs)
805+
{
806+
get_dependencies_from_generic_parameters_rec(t, refs);
807+
}

src/java_bytecode/java_types.h

+8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Author: Daniel Kroening, [email protected]
1111

1212
#include <util/invariant.h>
1313
#include <algorithm>
14+
#include <set>
1415

1516
#include <util/type.h>
1617
#include <util/std_types.h>
@@ -366,4 +367,11 @@ inline const optionalt<size_t> java_generics_get_index_for_subtype(
366367
return std::distance(gen_types.cbegin(), iter);
367368
}
368369

370+
void get_dependencies_from_generic_parameters(
371+
const std::string &,
372+
std::set<irep_idt> &);
373+
void get_dependencies_from_generic_parameters(
374+
const typet &,
375+
std::set<irep_idt> &);
376+
369377
#endif // CPROVER_JAVA_BYTECODE_JAVA_TYPES_H

src/java_bytecode/java_utils.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,15 @@ exprt make_function_application(
293293
call.arguments()=arguments;
294294
return call;
295295
}
296+
297+
/// Strip java:: prefix from given identifier
298+
/// \param to_strip: identifier from which the prefix is stripped
299+
/// \return the identifier without without java:: prefix
300+
irep_idt strip_java_namespace_prefix(const irep_idt &to_strip)
301+
{
302+
const std::string to_strip_str=id2string(to_strip);
303+
const std::string prefix="java::";
304+
305+
PRECONDITION(has_prefix(to_strip_str, prefix));
306+
return to_strip_str.substr(prefix.size(), std::string::npos);
307+
}

src/java_bytecode/java_utils.h

+2
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,6 @@ exprt make_function_application(
9292
const typet &type,
9393
symbol_table_baset &symbol_table);
9494

95+
irep_idt strip_java_namespace_prefix(const irep_idt &to_strip);
96+
9597
#endif // CPROVER_JAVA_BYTECODE_JAVA_UTILS_H

0 commit comments

Comments
 (0)