Skip to content

Commit 41d7a45

Browse files
Merge pull request diffblue#2129 from romainbrenguier/bugfix/generic_type_index
[TG-3374] Fix generic_type_index
2 parents 8127d4d + 53bc892 commit 41d7a45

15 files changed

+239
-27
lines changed
466 Bytes
Binary file not shown.
240 Bytes
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
645 Bytes
Binary file not shown.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
interface AbstractInt<K,V> { V get(); }
2+
3+
class AbstractImpl<K,V> implements AbstractInt<K,V> {
4+
V t;
5+
public V get() { return t; }
6+
}
7+
8+
public class AbstractTest {
9+
class Dummy { private boolean b; }
10+
class ClassA { private int id; }
11+
class ClassB {
12+
private int id;
13+
int getId() { return id; }
14+
}
15+
16+
public int getFromAbstract(AbstractInt<ClassA, ClassB> arg) {
17+
AbstractImpl<Dummy, Dummy> dummy = new AbstractImpl<>();
18+
ClassB b = arg.get();
19+
int i = b.getId();
20+
return i;
21+
}
22+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
AbstractTest.class
3+
--cover location --function AbstractTest.getFromAbstract
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
file AbstractTest.java line 18 .* SATISFIED
7+
file AbstractTest.java line 19 .* SATISFIED
8+
file AbstractTest.java line 20 .* SATISFIED
9+
file AbstractTest.java line 21 .* SATISFIED
10+
11+

src/java_bytecode/java_types.cpp

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,10 @@ size_t find_closing_semi_colon_for_reference_type(
416416
/// representation thereof.
417417
///
418418
/// Example use are object types like "Ljava/lang/Integer;", type
419-
/// variables/parameters like "TE;" which require a non-empty \p class_name
420-
/// or generic types like "Ljava/util/List<T>;" or "Ljava/util/List<Integer>;"
419+
/// variables/parameters like "TE;" which require a non-empty
420+
/// \p class_name_prefix or generic types like "Ljava/util/List<TE;>;"
421+
/// or "Ljava/util/List<Ljava/lang/Integer;>;" also requiring
422+
/// \p class_name_prefix.
421423
///
422424
/// \param src: the string representation as used in the class file
423425
/// \param class_name_prefix: name of class to append to generic type
@@ -833,3 +835,52 @@ void get_dependencies_from_generic_parameters(
833835
{
834836
get_dependencies_from_generic_parameters_rec(t, refs);
835837
}
838+
839+
/// Construct a generic symbol type by extending the symbol type \p type with
840+
/// generic types extracted from the reference \p base_ref.
841+
/// This assumes that the class named \p class_name_prefix extends or implements
842+
/// the class \p type, and that \p base_ref corresponds to a generic class.
843+
/// For instance since HashMap<K,V> extends Map<K,V> we would call
844+
/// `java_generic_symbol_typet(symbol_typet("Map"), "Ljava/util/Map<TK;TV;>;",
845+
/// "java.util.HashMap")` which generates a symbol type with identifier "Map",
846+
/// and two generic types with identifier "java.util.HashMap::K" and
847+
/// "java.util.HashMap::V" respectively.
848+
java_generic_symbol_typet::java_generic_symbol_typet(
849+
const symbol_typet &type,
850+
const std::string &base_ref,
851+
const std::string &class_name_prefix)
852+
: symbol_typet(type)
853+
{
854+
set(ID_C_java_generic_symbol, true);
855+
const typet &base_type = java_type_from_string(base_ref, class_name_prefix);
856+
PRECONDITION(is_java_generic_type(base_type));
857+
const java_generic_typet &gen_base_type = to_java_generic_type(base_type);
858+
INVARIANT(
859+
type.get_identifier() == to_symbol_type(gen_base_type.subtype()).get_identifier(),
860+
"identifier of "+type.pretty()+"\n and identifier of type "+
861+
gen_base_type.subtype().pretty()+"\ncreated by java_type_from_string for "+
862+
base_ref+" should be equal");
863+
generic_types().insert(
864+
generic_types().end(),
865+
gen_base_type.generic_type_arguments().begin(),
866+
gen_base_type.generic_type_arguments().end());
867+
}
868+
869+
/// Check if this symbol has the given generic type. If yes, return its index
870+
/// in the vector of generic types.
871+
/// \param type The parameter type we are looking for.
872+
/// \return The index of the type in the vector of generic types.
873+
optionalt<size_t> java_generic_symbol_typet::generic_type_index(
874+
const java_generic_parametert &type) const
875+
{
876+
const auto &type_variable = type.get_name();
877+
const auto &generics = generic_types();
878+
for(std::size_t i = 0; i < generics.size(); ++i)
879+
{
880+
if(
881+
is_java_generic_parameter(generics[i]) &&
882+
to_java_generic_parameter(generics[i]).get_name() == type_variable)
883+
return i;
884+
}
885+
return {};
886+
}

src/java_bytecode/java_types.h

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -582,18 +582,7 @@ class java_generic_symbol_typet : public symbol_typet
582582
java_generic_symbol_typet(
583583
const symbol_typet &type,
584584
const std::string &base_ref,
585-
const std::string &class_name_prefix)
586-
: symbol_typet(type)
587-
{
588-
set(ID_C_java_generic_symbol, true);
589-
const typet &base_type = java_type_from_string(base_ref, class_name_prefix);
590-
PRECONDITION(is_java_generic_type(base_type));
591-
const java_generic_typet gen_base_type = to_java_generic_type(base_type);
592-
generic_types().insert(
593-
generic_types().end(),
594-
gen_base_type.generic_type_arguments().begin(),
595-
gen_base_type.generic_type_arguments().end());
596-
}
585+
const std::string &class_name_prefix);
597586

598587
const generic_typest &generic_types() const
599588
{
@@ -605,18 +594,8 @@ class java_generic_symbol_typet : public symbol_typet
605594
return (generic_typest &)(add(ID_generic_types).get_sub());
606595
}
607596

608-
/// Check if this symbol has the given generic type. If yes, return its index
609-
/// in the vector of generic types.
610-
/// \param type The type we are looking for.
611-
/// \return The index of the type in the vector of generic types.
612-
optionalt<size_t> generic_type_index(const reference_typet &type) const
613-
{
614-
const auto &type_pointer =
615-
std::find(generic_types().begin(), generic_types().end(), type);
616-
if(type_pointer != generic_types().end())
617-
return type_pointer - generic_types().begin();
618-
return {};
619-
}
597+
optionalt<size_t>
598+
generic_type_index(const java_generic_parametert &type) const;
620599
};
621600

622601
/// \param type: the type to check

unit/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ SRC += unit_tests.cpp \
2424
java_bytecode/java_bytecode_parse_lambdas/java_bytecode_convert_class_lambda_method_handles.cpp \
2525
miniBDD_new.cpp \
2626
java_bytecode/java_string_library_preprocess/convert_exprt_to_string_exprt.cpp \
27+
java_bytecode/java_types/erase_type_arguments.cpp \
28+
java_bytecode/java_types/generic_type_index.cpp \
29+
java_bytecode/java_types/java_generic_symbol_type.cpp \
30+
java_bytecode/java_types/java_type_from_string.cpp \
2731
java_bytecode/java_utils_test.cpp \
2832
java_bytecode/inherited_static_fields/inherited_static_fields.cpp \
2933
pointer-analysis/custom_value_set_analysis.cpp \

unit/java_bytecode/java_types/erase_type_arguments.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
\*******************************************************************/
88

99
#include <testing-utils/catch.hpp>
10-
#include <java_types.h>
10+
#include <java_bytecode/java_types.h>
1111

1212
SCENARIO("erase_type_arguments", "[core][java_types]")
1313
{
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for java_types
4+
5+
Author: Diffblue Ltd.
6+
7+
\*******************************************************************/
8+
9+
#include <testing-utils/catch.hpp>
10+
#include <java_bytecode/java_types.h>
11+
12+
SCENARIO("generic_type_index", "[core][java_types]")
13+
{
14+
GIVEN("PrefixClassName<X, value> extends GenericClass<X,value>, "
15+
"and parameters X, value, Z")
16+
{
17+
const auto symbol_type = symbol_typet("java::GenericClass");
18+
const auto generic_symbol_type = java_generic_symbol_typet(
19+
symbol_type, "LGenericClass<TX;Tvalue;>;", "PrefixClassName");
20+
java_generic_parametert paramX("PrefixClassName::X", symbol_typet());
21+
java_generic_parametert value("PrefixClassName::value", symbol_typet());
22+
java_generic_parametert paramZ("PrefixClassName::Z", symbol_typet());
23+
24+
WHEN("Looking for parameter indexes")
25+
{
26+
const auto indexX = generic_symbol_type.generic_type_index(paramX);
27+
const auto index_value = generic_symbol_type.generic_type_index(value);
28+
const auto indexZ = generic_symbol_type.generic_type_index(paramZ);
29+
30+
THEN("X has index 0, Y index 1 and Z is not found")
31+
{
32+
REQUIRE(indexX.has_value());
33+
REQUIRE(indexX.value() == 0);
34+
REQUIRE(index_value.has_value());
35+
REQUIRE(index_value.value() == 1);
36+
REQUIRE_FALSE(indexZ.has_value());
37+
}
38+
}
39+
}
40+
41+
GIVEN("HashMap<K,V> extends Map<K,V>, and parameters K, V, T")
42+
{
43+
const auto symbol_type = symbol_typet("java::java.util.Map");
44+
const auto generic_symbol_type = java_generic_symbol_typet(
45+
symbol_type, "Ljava/util/Map<TK;TV;>;", "java.util.HashMap");
46+
java_generic_parametert param0("java.util.HashMap::K", symbol_typet());
47+
java_generic_parametert param1("java.util.HashMap::V", symbol_typet());
48+
java_generic_parametert param2("java.util.HashMap::T", symbol_typet());
49+
50+
WHEN("Looking for parameter indexes")
51+
{
52+
const auto index_param0 = generic_symbol_type.generic_type_index(param0);
53+
const auto index_param1 = generic_symbol_type.generic_type_index(param1);
54+
const auto index_param2 = generic_symbol_type.generic_type_index(param2);
55+
56+
THEN("K has index 0, V index 1 and T is not found")
57+
{
58+
REQUIRE(index_param0.has_value());
59+
REQUIRE(index_param0.value() == 0);
60+
REQUIRE(index_param1.has_value());
61+
REQUIRE(index_param1.value() == 1);
62+
REQUIRE_FALSE(index_param2.has_value());
63+
}
64+
}
65+
}
66+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for java_types
4+
5+
Author: Diffblue Ltd.
6+
7+
\*******************************************************************/
8+
9+
#include <testing-utils/catch.hpp>
10+
#include <java_bytecode/java_types.h>
11+
12+
SCENARIO("java_generic_symbol_type", "[core][java_types]")
13+
{
14+
GIVEN("LGenericClass<TX;TY;>;")
15+
{
16+
auto symbol_type = symbol_typet("java::GenericClass");
17+
const auto generic_symbol_type = java_generic_symbol_typet(
18+
symbol_type, "LGenericClass<TX;TY;>;", "PrefixClassName");
19+
20+
REQUIRE(generic_symbol_type.get_identifier() == "java::GenericClass");
21+
22+
auto types = generic_symbol_type.generic_types();
23+
REQUIRE(types.size() == 2);
24+
25+
auto generic_var0 = to_java_generic_parameter(types[0]).type_variable();
26+
REQUIRE(generic_var0.get_identifier() == "PrefixClassName::X");
27+
28+
auto generic_var1 = to_java_generic_parameter(types[1]).type_variable();
29+
REQUIRE(generic_var1.get_identifier() == "PrefixClassName::Y");
30+
}
31+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for java_types
4+
5+
Author: Diffblue Ltd.
6+
7+
\*******************************************************************/
8+
9+
#include <testing-utils/catch.hpp>
10+
#include <java_bytecode/java_types.h>
11+
12+
SCENARIO("java_type_from_string", "[core][java_types]")
13+
{
14+
// TODO : add more cases, the current test is not comprehensive
15+
16+
GIVEN("Ljava/lang/Integer;")
17+
{
18+
const auto integer_type = java_type_from_string("Ljava/lang/Integer;", "");
19+
REQUIRE(integer_type != nil_typet());
20+
}
21+
22+
GIVEN("TE;")
23+
{
24+
const auto generic_type_E = java_type_from_string("TE;", "MyClass");
25+
REQUIRE(generic_type_E != nil_typet());
26+
}
27+
28+
GIVEN("Ljava/util/List<TX;>;")
29+
{
30+
const auto generic_list_type =
31+
java_type_from_string("Ljava/util/List<TX;>;", "java.util.List");
32+
REQUIRE(generic_list_type != nil_typet());
33+
}
34+
35+
GIVEN("Ljava/util/List<Ljava/lang/Integer>;")
36+
{
37+
const auto integer_list_type =
38+
java_type_from_string("Ljava/util/List<Ljava/lang/Integer;>;", "");
39+
REQUIRE(integer_list_type != nil_typet());
40+
}
41+
42+
GIVEN("Ljava/util/Map<TK;TV;>;")
43+
{
44+
const auto generic_symbol_type =
45+
java_type_from_string("Ljava/util/Map<TK;TV;>;", "java.util.Map");
46+
REQUIRE(generic_symbol_type != nil_typet());
47+
}
48+
}

0 commit comments

Comments
 (0)