Skip to content

Commit deb2bf3

Browse files
Merge pull request #3599 from thomasspriggs/tas/inner_class_names
Add parsing of the names of inner java classes.
2 parents 9133f75 + 28fbcce commit deb2bf3

13 files changed

+170
-1
lines changed

jbmc/src/java_bytecode/java_bytecode_convert_class.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ void java_bytecode_convert_classt::convert(
303303
}
304304

305305
class_type.set_tag(c.name);
306+
class_type.set_inner_name(c.inner_name);
306307
class_type.set(ID_abstract, c.is_abstract);
307308
class_type.set(ID_is_annotation, c.is_annotation);
308309
class_type.set(ID_interface, c.is_interface);

jbmc/src/java_bytecode/java_bytecode_parse_tree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ struct java_bytecode_parse_treet
213213
classt &operator=(classt &&) = default;
214214
#endif
215215

216-
irep_idt name, super_class;
216+
irep_idt name, super_class, inner_name;
217217
bool is_abstract=false;
218218
bool is_enum=false;
219219
bool is_public=false, is_protected=false, is_private=false;

jbmc/src/java_bytecode/java_bytecode_parser.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,6 +1696,8 @@ void java_bytecode_parsert::rinner_classes_attribute(
16961696
// This is a marker that a class is anonymous.
16971697
if(inner_name_index == 0)
16981698
parsed_class.is_anonymous_class = true;
1699+
else
1700+
parsed_class.inner_name = pool_entry_lambda(inner_name_index).s;
16991701
// Note that if outer_class_info_index == 0, the inner class is an anonymous
17001702
// or local class, and is treated as private.
17011703
if(outer_class_info_index == 0)

jbmc/src/java_bytecode/java_types.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,18 @@ class java_class_typet:public class_typet
241241
{
242242
set(ID_name, name);
243243
}
244+
245+
/// Get the name of a java inner class.
246+
const irep_idt &get_inner_name() const
247+
{
248+
return get(ID_inner_name);
249+
}
250+
251+
/// Set the name of a java inner class.
252+
void set_inner_name(const irep_idt &name)
253+
{
254+
set(ID_inner_name, name);
255+
}
244256
};
245257

246258
inline const java_class_typet &to_java_class_type(const typet &type)

jbmc/unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ SRC += java_bytecode/ci_lazy_methods/lazy_load_lambdas.cpp \
3838
java_bytecode/java_bytecode_parse_lambdas/java_bytecode_convert_class_lambda_method_handles.cpp \
3939
java_bytecode/java_bytecode_parse_lambdas/java_bytecode_parse_lambda_method_table.cpp \
4040
java_bytecode/java_bytecode_parser/parse_class_without_instructions.cpp \
41+
java_bytecode/java_bytecode_parser/parse_inner_class.cpp \
4142
java_bytecode/java_bytecode_parser/parse_java_annotations.cpp \
4243
java_bytecode/java_bytecode_parser/parse_java_attributes.cpp \
4344
java_bytecode/java_bytecode_parser/parse_java_class.cpp \
Binary file not shown.
Binary file not shown.
Binary file not shown.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class Outer$RedHerring {
2+
}
Binary file not shown.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Outer {
2+
class Inner {
3+
}
4+
5+
Outer anonymous = new Outer() {
6+
};
7+
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*******************************************************************\
2+
3+
Module: Unit tests for converting inner classes
4+
5+
Author: Diffblue Ltd.
6+
7+
\*******************************************************************/
8+
9+
#include <java-testing-utils/load_java_class.h>
10+
#include <java_bytecode/java_types.h>
11+
#include <testing-utils/catch.hpp>
12+
13+
#include <string>
14+
#include <vector>
15+
16+
SCENARIO(
17+
"Parsing inner java classes",
18+
"[core][java_bytecode][java_bytecode_parser]")
19+
{
20+
for(const auto &load_first : std::vector<std::string>{"Outer$Inner", "Outer"})
21+
{
22+
const symbol_tablet &symbol_table =
23+
load_java_class(load_first, "./java_bytecode/java_bytecode_parser");
24+
25+
GIVEN("A class file of an inner class and " + load_first + " loaded first.")
26+
{
27+
WHEN("Parsing an inner class called \"Inner\".")
28+
{
29+
const symbolt *class_symbol = symbol_table.lookup("java::Outer$Inner");
30+
REQUIRE(class_symbol);
31+
const java_class_typet *class_type =
32+
type_try_dynamic_cast<java_class_typet>(class_symbol->type);
33+
REQUIRE(class_type);
34+
35+
THEN("The inner class should have the name \"java::Outer$Inner\".")
36+
{
37+
REQUIRE(id2string(class_type->get_name()) == "java::Outer$Inner");
38+
}
39+
THEN("The inner class should have the inner name \"Inner\".")
40+
{
41+
REQUIRE(id2string(class_type->get_inner_name()) == "Inner");
42+
}
43+
THEN("The inner class is not considered to be an anonymous class.")
44+
{
45+
REQUIRE_FALSE(class_type->get_is_anonymous_class());
46+
}
47+
THEN("The inner class has the outer class \"Outer\".")
48+
{
49+
REQUIRE(id2string(class_type->get_outer_class()) == "Outer");
50+
}
51+
}
52+
}
53+
GIVEN(
54+
"A class file of a class which is not an inner class and " + load_first +
55+
" loaded first.")
56+
{
57+
WHEN("Parsing an outer class.")
58+
{
59+
const symbolt *class_symbol = symbol_table.lookup("java::Outer");
60+
REQUIRE(class_symbol);
61+
const java_class_typet *class_type =
62+
type_try_dynamic_cast<java_class_typet>(class_symbol->type);
63+
REQUIRE(class_type);
64+
65+
THEN("The outer class should have the name \"java::Outer\".")
66+
{
67+
REQUIRE(id2string(class_type->get_name()) == "java::Outer");
68+
}
69+
THEN("The outer class should not have an inner name.")
70+
{
71+
REQUIRE(id2string(class_type->get_inner_name()).empty());
72+
}
73+
THEN("The outer class is not considered to be an anonymous class.")
74+
{
75+
REQUIRE_FALSE(class_type->get_is_anonymous_class());
76+
}
77+
THEN("The outer class does not have an outer class.")
78+
{
79+
REQUIRE(id2string(class_type->get_outer_class()).empty());
80+
}
81+
}
82+
}
83+
GIVEN(
84+
"A class file of an anonymous class and " + load_first + " loaded first.")
85+
{
86+
WHEN("Parsing an anonymous class.")
87+
{
88+
const symbolt *class_symbol = symbol_table.lookup("java::Outer$1");
89+
REQUIRE(class_symbol);
90+
const java_class_typet *class_type =
91+
type_try_dynamic_cast<java_class_typet>(class_symbol->type);
92+
REQUIRE(class_type);
93+
94+
THEN("The anonymous class should have the name \"java::Outer$1\".")
95+
{
96+
REQUIRE(id2string(class_type->get_name()) == "java::Outer$1");
97+
}
98+
THEN("The anonymous class should not have an inner name.")
99+
{
100+
REQUIRE(id2string(class_type->get_inner_name()).empty());
101+
}
102+
THEN("The anonymous class is considered to be an anonymous class.")
103+
{
104+
REQUIRE(class_type->get_is_anonymous_class());
105+
}
106+
THEN("The anonymous class does not have an outer class.")
107+
{
108+
REQUIRE(id2string(class_type->get_outer_class()).empty());
109+
}
110+
}
111+
}
112+
}
113+
GIVEN("A class file of an outer class which is named with a '$'.")
114+
{
115+
WHEN("Parsing an outer class named with a '$'.")
116+
{
117+
const symbol_tablet &symbol_table = load_java_class(
118+
"Outer$RedHerring", "./java_bytecode/java_bytecode_parser");
119+
const auto *class_symbol = symbol_table.lookup("java::Outer$RedHerring");
120+
REQUIRE(class_symbol);
121+
const java_class_typet *class_type =
122+
type_try_dynamic_cast<java_class_typet>(class_symbol->type);
123+
REQUIRE(class_type);
124+
125+
THEN("The outer class should have the name \"java::Outer$RedHerring\".")
126+
{
127+
REQUIRE(id2string(class_type->get_name()) == "java::Outer$RedHerring");
128+
}
129+
THEN("The outer class should not have an inner name.")
130+
{
131+
REQUIRE(id2string(class_type->get_inner_name()).empty());
132+
}
133+
THEN("The inner class is not considered to be an anonymous class.")
134+
{
135+
REQUIRE_FALSE(class_type->get_is_anonymous_class());
136+
}
137+
THEN("The outer class does not have an outer class.")
138+
{
139+
REQUIRE(id2string(class_type->get_outer_class()).empty());
140+
}
141+
}
142+
}
143+
}

src/util/irep_ids.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ IREP_ID_ONE(incomplete_c_enum)
131131
IREP_ID_TWO(C_incomplete, #incomplete)
132132
IREP_ID_ONE(identifier)
133133
IREP_ID_ONE(name)
134+
IREP_ID_ONE(inner_name)
134135
IREP_ID_ONE(cpp_name)
135136
IREP_ID_ONE(component_cpp_name)
136137
IREP_ID_TWO(C_id_class, #id_class)

0 commit comments

Comments
 (0)